aboutsummaryrefslogtreecommitdiffstats
path: root/arch/sparc
diff options
context:
space:
mode:
authorAl Viro <viro@zeniv.linux.org.uk>2012-10-05 22:37:01 -0400
committerAl Viro <viro@zeniv.linux.org.uk>2012-10-14 19:26:52 -0400
commit1918c7f548dc5abfb37ab74bb3d036d36c92ba5e (patch)
treec6f1a678fd6dac2ab93579a7246afb27cc7f9f26 /arch/sparc
parentdff933da765fd4855393846fa55286d1ff2d024a (diff)
sparc64: switch to generic kernel_thread()
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Diffstat (limited to 'arch/sparc')
-rw-r--r--arch/sparc/Kconfig1
-rw-r--r--arch/sparc/include/asm/processor_64.h2
-rw-r--r--arch/sparc/include/asm/ptrace.h3
-rw-r--r--arch/sparc/kernel/process_64.c107
-rw-r--r--arch/sparc/kernel/syscalls.S11
5 files changed, 42 insertions, 82 deletions
diff --git a/arch/sparc/Kconfig b/arch/sparc/Kconfig
index b6b442b0d793..ab8bd62b8dbe 100644
--- a/arch/sparc/Kconfig
+++ b/arch/sparc/Kconfig
@@ -74,6 +74,7 @@ config SPARC64
74 select ARCH_HAVE_NMI_SAFE_CMPXCHG 74 select ARCH_HAVE_NMI_SAFE_CMPXCHG
75 select HAVE_C_RECORDMCOUNT 75 select HAVE_C_RECORDMCOUNT
76 select NO_BOOTMEM 76 select NO_BOOTMEM
77 select GENERIC_KERNEL_THREAD
77 78
78config ARCH_DEFCONFIG 79config ARCH_DEFCONFIG
79 string 80 string
diff --git a/arch/sparc/include/asm/processor_64.h b/arch/sparc/include/asm/processor_64.h
index 4e5a483122a0..5d81ff6b6933 100644
--- a/arch/sparc/include/asm/processor_64.h
+++ b/arch/sparc/include/asm/processor_64.h
@@ -188,8 +188,6 @@ do { \
188/* Free all resources held by a thread. */ 188/* Free all resources held by a thread. */
189#define release_thread(tsk) do { } while (0) 189#define release_thread(tsk) do { } while (0)
190 190
191extern pid_t kernel_thread(int (*fn)(void *), void * arg, unsigned long flags);
192
193extern unsigned long get_wchan(struct task_struct *task); 191extern unsigned long get_wchan(struct task_struct *task);
194 192
195#define task_pt_regs(tsk) (task_thread_info(tsk)->kregs) 193#define task_pt_regs(tsk) (task_thread_info(tsk)->kregs)
diff --git a/arch/sparc/include/asm/ptrace.h b/arch/sparc/include/asm/ptrace.h
index 5b6019e327e5..7a4075003e76 100644
--- a/arch/sparc/include/asm/ptrace.h
+++ b/arch/sparc/include/asm/ptrace.h
@@ -32,6 +32,9 @@ static inline bool pt_regs_clear_syscall(struct pt_regs *regs)
32#define arch_ptrace_stop(exit_code, info) \ 32#define arch_ptrace_stop(exit_code, info) \
33 synchronize_user_stack() 33 synchronize_user_stack()
34 34
35#define current_pt_regs() \
36 ((struct pt_regs *)((unsigned long)current_thread_info() + THREAD_SIZE) - 1)
37
35struct global_reg_snapshot { 38struct global_reg_snapshot {
36 unsigned long tstate; 39 unsigned long tstate;
37 unsigned long tpc; 40 unsigned long tpc;
diff --git a/arch/sparc/kernel/process_64.c b/arch/sparc/kernel/process_64.c
index 4c864c796507..e37512319296 100644
--- a/arch/sparc/kernel/process_64.c
+++ b/arch/sparc/kernel/process_64.c
@@ -538,64 +538,56 @@ asmlinkage long sparc_do_fork(unsigned long clone_flags,
538 * Child --> %o0 == parents pid, %o1 == 1 538 * Child --> %o0 == parents pid, %o1 == 1
539 */ 539 */
540int copy_thread(unsigned long clone_flags, unsigned long sp, 540int copy_thread(unsigned long clone_flags, unsigned long sp,
541 unsigned long unused, 541 unsigned long arg,
542 struct task_struct *p, struct pt_regs *regs) 542 struct task_struct *p, struct pt_regs *regs)
543{ 543{
544 struct thread_info *t = task_thread_info(p); 544 struct thread_info *t = task_thread_info(p);
545 struct sparc_stackf *parent_sf; 545 struct sparc_stackf *parent_sf;
546 unsigned long child_stack_sz; 546 unsigned long child_stack_sz;
547 char *child_trap_frame; 547 char *child_trap_frame;
548 int kernel_thread;
549
550 kernel_thread = (regs->tstate & TSTATE_PRIV) ? 1 : 0;
551 parent_sf = ((struct sparc_stackf *) regs) - 1;
552 548
553 /* Calculate offset to stack_frame & pt_regs */ 549 /* Calculate offset to stack_frame & pt_regs */
554 child_stack_sz = ((STACKFRAME_SZ + TRACEREG_SZ) + 550 child_stack_sz = (STACKFRAME_SZ + TRACEREG_SZ);
555 (kernel_thread ? STACKFRAME_SZ : 0));
556 child_trap_frame = (task_stack_page(p) + 551 child_trap_frame = (task_stack_page(p) +
557 (THREAD_SIZE - child_stack_sz)); 552 (THREAD_SIZE - child_stack_sz));
558 memcpy(child_trap_frame, parent_sf, child_stack_sz);
559 553
560 __thread_flag_byte_ptr(t)[TI_FLAG_BYTE_CWP] =
561 (regs->tstate + 1) & TSTATE_CWP;
562 t->new_child = 1; 554 t->new_child = 1;
563 t->ksp = ((unsigned long) child_trap_frame) - STACK_BIAS; 555 t->ksp = ((unsigned long) child_trap_frame) - STACK_BIAS;
564 t->kregs = (struct pt_regs *) (child_trap_frame + 556 t->kregs = (struct pt_regs *) (child_trap_frame +
565 sizeof(struct sparc_stackf)); 557 sizeof(struct sparc_stackf));
566 t->fpsaved[0] = 0; 558 t->fpsaved[0] = 0;
567 559
568 if (kernel_thread) { 560 if (unlikely(p->flags & PF_KTHREAD)) {
569 struct sparc_stackf *child_sf = (struct sparc_stackf *) 561 memset(child_trap_frame, 0, child_stack_sz);
570 (child_trap_frame + (STACKFRAME_SZ + TRACEREG_SZ)); 562 __thread_flag_byte_ptr(t)[TI_FLAG_BYTE_CWP] =
571 563 (current_pt_regs()->tstate + 1) & TSTATE_CWP;
572 /* Zero terminate the stack backtrace. */
573 child_sf->fp = NULL;
574 t->kregs->u_regs[UREG_FP] =
575 ((unsigned long) child_sf) - STACK_BIAS;
576
577 t->current_ds = ASI_P; 564 t->current_ds = ASI_P;
578 t->kregs->u_regs[UREG_G6] = (unsigned long) t; 565 t->kregs->u_regs[UREG_G1] = sp; /* function */
579 t->kregs->u_regs[UREG_G4] = (unsigned long) t->task; 566 t->kregs->u_regs[UREG_G2] = arg;
580 } else { 567 return 0;
581 if (t->flags & _TIF_32BIT) {
582 sp &= 0x00000000ffffffffUL;
583 regs->u_regs[UREG_FP] &= 0x00000000ffffffffUL;
584 }
585 t->kregs->u_regs[UREG_FP] = sp;
586 t->current_ds = ASI_AIUS;
587 if (sp != regs->u_regs[UREG_FP]) {
588 unsigned long csp;
589
590 csp = clone_stackframe(sp, regs->u_regs[UREG_FP]);
591 if (!csp)
592 return -EFAULT;
593 t->kregs->u_regs[UREG_FP] = csp;
594 }
595 if (t->utraps)
596 t->utraps[0]++;
597 } 568 }
598 569
570 parent_sf = ((struct sparc_stackf *) regs) - 1;
571 memcpy(child_trap_frame, parent_sf, child_stack_sz);
572 if (t->flags & _TIF_32BIT) {
573 sp &= 0x00000000ffffffffUL;
574 regs->u_regs[UREG_FP] &= 0x00000000ffffffffUL;
575 }
576 t->kregs->u_regs[UREG_FP] = sp;
577 __thread_flag_byte_ptr(t)[TI_FLAG_BYTE_CWP] =
578 (regs->tstate + 1) & TSTATE_CWP;
579 t->current_ds = ASI_AIUS;
580 if (sp != regs->u_regs[UREG_FP]) {
581 unsigned long csp;
582
583 csp = clone_stackframe(sp, regs->u_regs[UREG_FP]);
584 if (!csp)
585 return -EFAULT;
586 t->kregs->u_regs[UREG_FP] = csp;
587 }
588 if (t->utraps)
589 t->utraps[0]++;
590
599 /* Set the return value for the child. */ 591 /* Set the return value for the child. */
600 t->kregs->u_regs[UREG_I0] = current->pid; 592 t->kregs->u_regs[UREG_I0] = current->pid;
601 t->kregs->u_regs[UREG_I1] = 1; 593 t->kregs->u_regs[UREG_I1] = 1;
@@ -609,45 +601,6 @@ int copy_thread(unsigned long clone_flags, unsigned long sp,
609 return 0; 601 return 0;
610} 602}
611 603
612/*
613 * This is the mechanism for creating a new kernel thread.
614 *
615 * NOTE! Only a kernel-only process(ie the swapper or direct descendants
616 * who haven't done an "execve()") should use this: it will work within
617 * a system call from a "real" process, but the process memory space will
618 * not be freed until both the parent and the child have exited.
619 */
620pid_t kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
621{
622 long retval;
623
624 /* If the parent runs before fn(arg) is called by the child,
625 * the input registers of this function can be clobbered.
626 * So we stash 'fn' and 'arg' into global registers which
627 * will not be modified by the parent.
628 */
629 __asm__ __volatile__("mov %4, %%g2\n\t" /* Save FN into global */
630 "mov %5, %%g3\n\t" /* Save ARG into global */
631 "mov %1, %%g1\n\t" /* Clone syscall nr. */
632 "mov %2, %%o0\n\t" /* Clone flags. */
633 "mov 0, %%o1\n\t" /* usp arg == 0 */
634 "t 0x6d\n\t" /* Linux/Sparc clone(). */
635 "brz,a,pn %%o1, 1f\n\t" /* Parent, just return. */
636 " mov %%o0, %0\n\t"
637 "jmpl %%g2, %%o7\n\t" /* Call the function. */
638 " mov %%g3, %%o0\n\t" /* Set arg in delay. */
639 "mov %3, %%g1\n\t"
640 "t 0x6d\n\t" /* Linux/Sparc exit(). */
641 /* Notreached by child. */
642 "1:" :
643 "=r" (retval) :
644 "i" (__NR_clone), "r" (flags | CLONE_VM | CLONE_UNTRACED),
645 "i" (__NR_exit), "r" (fn), "r" (arg) :
646 "g1", "g2", "g3", "o0", "o1", "memory", "cc");
647 return retval;
648}
649EXPORT_SYMBOL(kernel_thread);
650
651typedef struct { 604typedef struct {
652 union { 605 union {
653 unsigned int pr_regs[32]; 606 unsigned int pr_regs[32];
diff --git a/arch/sparc/kernel/syscalls.S b/arch/sparc/kernel/syscalls.S
index b0ac10306425..624f34162c38 100644
--- a/arch/sparc/kernel/syscalls.S
+++ b/arch/sparc/kernel/syscalls.S
@@ -112,11 +112,16 @@ sys_clone:
112ret_from_syscall: 112ret_from_syscall:
113 /* Clear current_thread_info()->new_child. */ 113 /* Clear current_thread_info()->new_child. */
114 stb %g0, [%g6 + TI_NEW_CHILD] 114 stb %g0, [%g6 + TI_NEW_CHILD]
115 ldx [%g6 + TI_FLAGS], %l0
116 call schedule_tail 115 call schedule_tail
117 mov %g7, %o0 116 mov %g7, %o0
118 ba,pt %xcc, ret_sys_call 117 ldx [%sp + PTREGS_OFF + PT_V9_I0], %o0
119 ldx [%sp + PTREGS_OFF + PT_V9_I0], %o0 118 brnz,a,pt %o0, ret_sys_call
119 ldx [%g6 + TI_FLAGS], %l0
120 ldx [%sp + PTREGS_OFF + PT_V9_G1], %l0
121 call %l0
122 ldx [%sp + PTREGS_OFF + PT_V9_G2], %o0
123 call do_exit ! will not return
124 mov 0,%o0
120 125
121 .globl sparc_exit 126 .globl sparc_exit
122 .type sparc_exit,#function 127 .type sparc_exit,#function