aboutsummaryrefslogtreecommitdiffstats
path: root/arch/sparc
diff options
context:
space:
mode:
Diffstat (limited to 'arch/sparc')
-rw-r--r--arch/sparc/Kconfig2
-rw-r--r--arch/sparc/include/asm/processor_32.h1
-rw-r--r--arch/sparc/kernel/entry.S10
-rw-r--r--arch/sparc/kernel/process_32.c124
4 files changed, 56 insertions, 81 deletions
diff --git a/arch/sparc/Kconfig b/arch/sparc/Kconfig
index e47eb324d77a..edc4ede8ec3e 100644
--- a/arch/sparc/Kconfig
+++ b/arch/sparc/Kconfig
@@ -40,6 +40,7 @@ config SPARC
40 select GENERIC_STRNCPY_FROM_USER 40 select GENERIC_STRNCPY_FROM_USER
41 select GENERIC_STRNLEN_USER 41 select GENERIC_STRNLEN_USER
42 select MODULES_USE_ELF_RELA 42 select MODULES_USE_ELF_RELA
43 select GENERIC_KERNEL_THREAD
43 44
44config SPARC32 45config SPARC32
45 def_bool !64BIT 46 def_bool !64BIT
@@ -74,7 +75,6 @@ config SPARC64
74 select ARCH_HAVE_NMI_SAFE_CMPXCHG 75 select ARCH_HAVE_NMI_SAFE_CMPXCHG
75 select HAVE_C_RECORDMCOUNT 76 select HAVE_C_RECORDMCOUNT
76 select NO_BOOTMEM 77 select NO_BOOTMEM
77 select GENERIC_KERNEL_THREAD
78 select GENERIC_KERNEL_EXECVE 78 select GENERIC_KERNEL_EXECVE
79 79
80config ARCH_DEFCONFIG 80config ARCH_DEFCONFIG
diff --git a/arch/sparc/include/asm/processor_32.h b/arch/sparc/include/asm/processor_32.h
index f74ac9ee33a8..c1e01914fd98 100644
--- a/arch/sparc/include/asm/processor_32.h
+++ b/arch/sparc/include/asm/processor_32.h
@@ -106,7 +106,6 @@ static inline void start_thread(struct pt_regs * regs, unsigned long pc,
106 106
107/* Free all resources held by a thread. */ 107/* Free all resources held by a thread. */
108#define release_thread(tsk) do { } while(0) 108#define release_thread(tsk) do { } while(0)
109extern pid_t kernel_thread(int (*fn)(void *), void * arg, unsigned long flags);
110 109
111extern unsigned long get_wchan(struct task_struct *); 110extern unsigned long get_wchan(struct task_struct *);
112 111
diff --git a/arch/sparc/kernel/entry.S b/arch/sparc/kernel/entry.S
index dc089702e00a..6114672a1b0e 100644
--- a/arch/sparc/kernel/entry.S
+++ b/arch/sparc/kernel/entry.S
@@ -983,6 +983,16 @@ ret_from_fork:
983 b ret_sys_call 983 b ret_sys_call
984 ld [%sp + STACKFRAME_SZ + PT_I0], %o0 984 ld [%sp + STACKFRAME_SZ + PT_I0], %o0
985 985
986 .globl ret_from_kernel_thread
987ret_from_kernel_thread:
988 call schedule_tail
989 ld [%g3 + TI_TASK], %o0
990 ld [%sp + STACKFRAME_SZ + PT_G1], %l0
991 call %l0
992 ld [%sp + STACKFRAME_SZ + PT_G2], %o0
993 call do_exit /* won't return */
994 clr %o0
995
986 /* Linux native system calls enter here... */ 996 /* Linux native system calls enter here... */
987 .align 4 997 .align 4
988 .globl linux_sparc_syscall 998 .globl linux_sparc_syscall
diff --git a/arch/sparc/kernel/process_32.c b/arch/sparc/kernel/process_32.c
index 487bffb36f5e..72764356d308 100644
--- a/arch/sparc/kernel/process_32.c
+++ b/arch/sparc/kernel/process_32.c
@@ -316,9 +316,10 @@ asmlinkage int sparc_do_fork(unsigned long clone_flags,
316 * XXX See comment above sys_vfork in sparc64. todo. 316 * XXX See comment above sys_vfork in sparc64. todo.
317 */ 317 */
318extern void ret_from_fork(void); 318extern void ret_from_fork(void);
319extern void ret_from_kernel_thread(void);
319 320
320int copy_thread(unsigned long clone_flags, unsigned long sp, 321int copy_thread(unsigned long clone_flags, unsigned long sp,
321 unsigned long unused, 322 unsigned long arg,
322 struct task_struct *p, struct pt_regs *regs) 323 struct task_struct *p, struct pt_regs *regs)
323{ 324{
324 struct thread_info *ti = task_thread_info(p); 325 struct thread_info *ti = task_thread_info(p);
@@ -336,16 +337,13 @@ int copy_thread(unsigned long clone_flags, unsigned long sp,
336 } 337 }
337 338
338 /* 339 /*
339 * p->thread_info new_stack childregs 340 * p->thread_info new_stack childregs stack bottom
340 * ! ! ! {if(PSR_PS) } 341 * ! ! ! !
341 * V V (stk.fr.) V (pt_regs) { (stk.fr.) } 342 * V V (stk.fr.) V (pt_regs) V
342 * +----- - - - - - ------+===========+============={+==========}+ 343 * +----- - - - - - ------+===========+=============+
343 */ 344 */
344 new_stack = task_stack_page(p) + THREAD_SIZE; 345 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; 346 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); 347 childregs = (struct pt_regs *) (new_stack + STACKFRAME_SZ);
350 348
351 /* 349 /*
@@ -356,55 +354,58 @@ int copy_thread(unsigned long clone_flags, unsigned long sp,
356 * Thus, kpsr|=PSR_PIL. 354 * Thus, kpsr|=PSR_PIL.
357 */ 355 */
358 ti->ksp = (unsigned long) new_stack; 356 ti->ksp = (unsigned long) new_stack;
357 p->thread.kregs = childregs;
358
359 if (unlikely(p->flags & PF_KTHREAD)) {
360 extern int nwindows;
361 unsigned long psr;
362 memset(new_stack, 0, STACKFRAME_SZ + TRACEREG_SZ);
363 p->thread.flags |= SPARC_FLAG_KTHREAD;
364 p->thread.current_ds = KERNEL_DS;
365 ti->kpc = (((unsigned long) ret_from_kernel_thread) - 0x8);
366 childregs->u_regs[UREG_G1] = sp; /* function */
367 childregs->u_regs[UREG_G2] = arg;
368 psr = childregs->psr = get_psr();
369 ti->kpsr = psr | PSR_PIL;
370 ti->kwim = 1 << (((psr & PSR_CWP) + 1) % nwindows);
371 return 0;
372 }
373 memcpy(new_stack, (char *)regs - STACKFRAME_SZ, STACKFRAME_SZ + TRACEREG_SZ);
374 childregs->u_regs[UREG_FP] = sp;
375 p->thread.flags &= ~SPARC_FLAG_KTHREAD;
376 p->thread.current_ds = USER_DS;
359 ti->kpc = (((unsigned long) ret_from_fork) - 0x8); 377 ti->kpc = (((unsigned long) ret_from_fork) - 0x8);
360 ti->kpsr = current->thread.fork_kpsr | PSR_PIL; 378 ti->kpsr = current->thread.fork_kpsr | PSR_PIL;
361 ti->kwim = current->thread.fork_kwim; 379 ti->kwim = current->thread.fork_kwim;
362 380
363 if(regs->psr & PSR_PS) { 381 if (sp != regs->u_regs[UREG_FP]) {
364 extern struct pt_regs fake_swapper_regs; 382 struct sparc_stackf __user *childstack;
383 struct sparc_stackf __user *parentstack;
365 384
366 p->thread.kregs = &fake_swapper_regs; 385 /*
367 new_stack += STACKFRAME_SZ + TRACEREG_SZ; 386 * This is a clone() call with supplied user stack.
368 childregs->u_regs[UREG_FP] = (unsigned long) new_stack; 387 * Set some valid stack frames to give to the child.
369 p->thread.flags |= SPARC_FLAG_KTHREAD; 388 */
370 p->thread.current_ds = KERNEL_DS; 389 childstack = (struct sparc_stackf __user *)
371 memcpy(new_stack, (void *)regs->u_regs[UREG_FP], STACKFRAME_SZ); 390 (sp & ~0xfUL);
372 childregs->u_regs[UREG_G6] = (unsigned long) ti; 391 parentstack = (struct sparc_stackf __user *)
373 } else { 392 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 393
392#if 0 394#if 0
393 printk("clone: parent stack:\n"); 395 printk("clone: parent stack:\n");
394 show_stackframe(parentstack); 396 show_stackframe(parentstack);
395#endif 397#endif
396 398
397 childstack = clone_stackframe(childstack, parentstack); 399 childstack = clone_stackframe(childstack, parentstack);
398 if (!childstack) 400 if (!childstack)
399 return -EFAULT; 401 return -EFAULT;
400 402
401#if 0 403#if 0
402 printk("clone: child stack:\n"); 404 printk("clone: child stack:\n");
403 show_stackframe(childstack); 405 show_stackframe(childstack);
404#endif 406#endif
405 407
406 childregs->u_regs[UREG_FP] = (unsigned long)childstack; 408 childregs->u_regs[UREG_FP] = (unsigned long)childstack;
407 }
408 } 409 }
409 410
410#ifdef CONFIG_SMP 411#ifdef CONFIG_SMP
@@ -503,41 +504,6 @@ out:
503 return error; 504 return error;
504} 505}
505 506
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) 507unsigned long get_wchan(struct task_struct *task)
542{ 508{
543 unsigned long pc, fp, bias = 0; 509 unsigned long pc, fp, bias = 0;