aboutsummaryrefslogtreecommitdiffstats
path: root/arch/sparc/kernel/process_32.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/sparc/kernel/process_32.c')
-rw-r--r--arch/sparc/kernel/process_32.c158
1 files changed, 47 insertions, 111 deletions
diff --git a/arch/sparc/kernel/process_32.c b/arch/sparc/kernel/process_32.c
index 487bffb36f5e..be8e862badaf 100644
--- a/arch/sparc/kernel/process_32.c
+++ b/arch/sparc/kernel/process_32.c
@@ -286,8 +286,7 @@ asmlinkage int sparc_do_fork(unsigned long clone_flags,
286 parent_tid_ptr = regs->u_regs[UREG_I2]; 286 parent_tid_ptr = regs->u_regs[UREG_I2];
287 child_tid_ptr = regs->u_regs[UREG_I4]; 287 child_tid_ptr = regs->u_regs[UREG_I4];
288 288
289 ret = do_fork(clone_flags, stack_start, 289 ret = do_fork(clone_flags, stack_start, stack_size,
290 regs, stack_size,
291 (int __user *) parent_tid_ptr, 290 (int __user *) parent_tid_ptr,
292 (int __user *) child_tid_ptr); 291 (int __user *) child_tid_ptr);
293 292
@@ -316,13 +315,13 @@ asmlinkage int sparc_do_fork(unsigned long clone_flags,
316 * XXX See comment above sys_vfork in sparc64. todo. 315 * XXX See comment above sys_vfork in sparc64. todo.
317 */ 316 */
318extern void ret_from_fork(void); 317extern void ret_from_fork(void);
318extern void ret_from_kernel_thread(void);
319 319
320int copy_thread(unsigned long clone_flags, unsigned long sp, 320int copy_thread(unsigned long clone_flags, unsigned long sp,
321 unsigned long unused, 321 unsigned long arg, struct task_struct *p)
322 struct task_struct *p, struct pt_regs *regs)
323{ 322{
324 struct thread_info *ti = task_thread_info(p); 323 struct thread_info *ti = task_thread_info(p);
325 struct pt_regs *childregs; 324 struct pt_regs *childregs, *regs = current_pt_regs();
326 char *new_stack; 325 char *new_stack;
327 326
328#ifndef CONFIG_SMP 327#ifndef CONFIG_SMP
@@ -336,16 +335,13 @@ int copy_thread(unsigned long clone_flags, unsigned long sp,
336 } 335 }
337 336
338 /* 337 /*
339 * p->thread_info new_stack childregs 338 * p->thread_info new_stack childregs stack bottom
340 * ! ! ! {if(PSR_PS) } 339 * ! ! ! !
341 * V V (stk.fr.) V (pt_regs) { (stk.fr.) } 340 * V V (stk.fr.) V (pt_regs) V
342 * +----- - - - - - ------+===========+============={+==========}+ 341 * +----- - - - - - ------+===========+=============+
343 */ 342 */
344 new_stack = task_stack_page(p) + THREAD_SIZE; 343 new_stack = task_stack_page(p) + THREAD_SIZE;
345 if (regs->psr & PSR_PS)
346 new_stack -= STACKFRAME_SZ;
347 new_stack -= STACKFRAME_SZ + TRACEREG_SZ; 344 new_stack -= STACKFRAME_SZ + TRACEREG_SZ;
348 memcpy(new_stack, (char *)regs - STACKFRAME_SZ, STACKFRAME_SZ + TRACEREG_SZ);
349 childregs = (struct pt_regs *) (new_stack + STACKFRAME_SZ); 345 childregs = (struct pt_regs *) (new_stack + STACKFRAME_SZ);
350 346
351 /* 347 /*
@@ -356,55 +352,58 @@ int copy_thread(unsigned long clone_flags, unsigned long sp,
356 * Thus, kpsr|=PSR_PIL. 352 * Thus, kpsr|=PSR_PIL.
357 */ 353 */
358 ti->ksp = (unsigned long) new_stack; 354 ti->ksp = (unsigned long) new_stack;
355 p->thread.kregs = childregs;
356
357 if (unlikely(p->flags & PF_KTHREAD)) {
358 extern int nwindows;
359 unsigned long psr;
360 memset(new_stack, 0, STACKFRAME_SZ + TRACEREG_SZ);
361 p->thread.flags |= SPARC_FLAG_KTHREAD;
362 p->thread.current_ds = KERNEL_DS;
363 ti->kpc = (((unsigned long) ret_from_kernel_thread) - 0x8);
364 childregs->u_regs[UREG_G1] = sp; /* function */
365 childregs->u_regs[UREG_G2] = arg;
366 psr = childregs->psr = get_psr();
367 ti->kpsr = psr | PSR_PIL;
368 ti->kwim = 1 << (((psr & PSR_CWP) + 1) % nwindows);
369 return 0;
370 }
371 memcpy(new_stack, (char *)regs - STACKFRAME_SZ, STACKFRAME_SZ + TRACEREG_SZ);
372 childregs->u_regs[UREG_FP] = sp;
373 p->thread.flags &= ~SPARC_FLAG_KTHREAD;
374 p->thread.current_ds = USER_DS;
359 ti->kpc = (((unsigned long) ret_from_fork) - 0x8); 375 ti->kpc = (((unsigned long) ret_from_fork) - 0x8);
360 ti->kpsr = current->thread.fork_kpsr | PSR_PIL; 376 ti->kpsr = current->thread.fork_kpsr | PSR_PIL;
361 ti->kwim = current->thread.fork_kwim; 377 ti->kwim = current->thread.fork_kwim;
362 378
363 if(regs->psr & PSR_PS) { 379 if (sp != regs->u_regs[UREG_FP]) {
364 extern struct pt_regs fake_swapper_regs; 380 struct sparc_stackf __user *childstack;
381 struct sparc_stackf __user *parentstack;
365 382
366 p->thread.kregs = &fake_swapper_regs; 383 /*
367 new_stack += STACKFRAME_SZ + TRACEREG_SZ; 384 * This is a clone() call with supplied user stack.
368 childregs->u_regs[UREG_FP] = (unsigned long) new_stack; 385 * Set some valid stack frames to give to the child.
369 p->thread.flags |= SPARC_FLAG_KTHREAD; 386 */
370 p->thread.current_ds = KERNEL_DS; 387 childstack = (struct sparc_stackf __user *)
371 memcpy(new_stack, (void *)regs->u_regs[UREG_FP], STACKFRAME_SZ); 388 (sp & ~0xfUL);
372 childregs->u_regs[UREG_G6] = (unsigned long) ti; 389 parentstack = (struct sparc_stackf __user *)
373 } else { 390 regs->u_regs[UREG_FP];
374 p->thread.kregs = childregs;
375 childregs->u_regs[UREG_FP] = sp;
376 p->thread.flags &= ~SPARC_FLAG_KTHREAD;
377 p->thread.current_ds = USER_DS;
378
379 if (sp != regs->u_regs[UREG_FP]) {
380 struct sparc_stackf __user *childstack;
381 struct sparc_stackf __user *parentstack;
382
383 /*
384 * This is a clone() call with supplied user stack.
385 * Set some valid stack frames to give to the child.
386 */
387 childstack = (struct sparc_stackf __user *)
388 (sp & ~0xfUL);
389 parentstack = (struct sparc_stackf __user *)
390 regs->u_regs[UREG_FP];
391 391
392#if 0 392#if 0
393 printk("clone: parent stack:\n"); 393 printk("clone: parent stack:\n");
394 show_stackframe(parentstack); 394 show_stackframe(parentstack);
395#endif 395#endif
396 396
397 childstack = clone_stackframe(childstack, parentstack); 397 childstack = clone_stackframe(childstack, parentstack);
398 if (!childstack) 398 if (!childstack)
399 return -EFAULT; 399 return -EFAULT;
400 400
401#if 0 401#if 0
402 printk("clone: child stack:\n"); 402 printk("clone: child stack:\n");
403 show_stackframe(childstack); 403 show_stackframe(childstack);
404#endif 404#endif
405 405
406 childregs->u_regs[UREG_FP] = (unsigned long)childstack; 406 childregs->u_regs[UREG_FP] = (unsigned long)childstack;
407 }
408 } 407 }
409 408
410#ifdef CONFIG_SMP 409#ifdef CONFIG_SMP
@@ -475,69 +474,6 @@ int dump_fpu (struct pt_regs * regs, elf_fpregset_t * fpregs)
475 return 1; 474 return 1;
476} 475}
477 476
478/*
479 * sparc_execve() executes a new program after the asm stub has set
480 * things up for us. This should basically do what I want it to.
481 */
482asmlinkage int sparc_execve(struct pt_regs *regs)
483{
484 int error, base = 0;
485 struct filename *filename;
486
487 /* Check for indirect call. */
488 if(regs->u_regs[UREG_G1] == 0)
489 base = 1;
490
491 filename = getname((char __user *)regs->u_regs[base + UREG_I0]);
492 error = PTR_ERR(filename);
493 if(IS_ERR(filename))
494 goto out;
495 error = do_execve(filename->name,
496 (const char __user *const __user *)
497 regs->u_regs[base + UREG_I1],
498 (const char __user *const __user *)
499 regs->u_regs[base + UREG_I2],
500 regs);
501 putname(filename);
502out:
503 return error;
504}
505
506/*
507 * This is the mechanism for creating a new kernel thread.
508 *
509 * NOTE! Only a kernel-only process(ie the swapper or direct descendants
510 * who haven't done an "execve()") should use this: it will work within
511 * a system call from a "real" process, but the process memory space will
512 * not be freed until both the parent and the child have exited.
513 */
514pid_t kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
515{
516 long retval;
517
518 __asm__ __volatile__("mov %4, %%g2\n\t" /* Set aside fn ptr... */
519 "mov %5, %%g3\n\t" /* and arg. */
520 "mov %1, %%g1\n\t"
521 "mov %2, %%o0\n\t" /* Clone flags. */
522 "mov 0, %%o1\n\t" /* usp arg == 0 */
523 "t 0x10\n\t" /* Linux/Sparc clone(). */
524 "cmp %%o1, 0\n\t"
525 "be 1f\n\t" /* The parent, just return. */
526 " nop\n\t" /* Delay slot. */
527 "jmpl %%g2, %%o7\n\t" /* Call the function. */
528 " mov %%g3, %%o0\n\t" /* Get back the arg in delay. */
529 "mov %3, %%g1\n\t"
530 "t 0x10\n\t" /* Linux/Sparc exit(). */
531 /* Notreached by child. */
532 "1: mov %%o0, %0\n\t" :
533 "=r" (retval) :
534 "i" (__NR_clone), "r" (flags | CLONE_VM | CLONE_UNTRACED),
535 "i" (__NR_exit), "r" (fn), "r" (arg) :
536 "g1", "g2", "g3", "o0", "o1", "memory", "cc");
537 return retval;
538}
539EXPORT_SYMBOL(kernel_thread);
540
541unsigned long get_wchan(struct task_struct *task) 477unsigned long get_wchan(struct task_struct *task)
542{ 478{
543 unsigned long pc, fp, bias = 0; 479 unsigned long pc, fp, bias = 0;