diff options
author | Al Viro <viro@zeniv.linux.org.uk> | 2012-10-05 22:37:01 -0400 |
---|---|---|
committer | Al Viro <viro@zeniv.linux.org.uk> | 2012-10-14 19:26:52 -0400 |
commit | 1918c7f548dc5abfb37ab74bb3d036d36c92ba5e (patch) | |
tree | c6f1a678fd6dac2ab93579a7246afb27cc7f9f26 /arch/sparc | |
parent | dff933da765fd4855393846fa55286d1ff2d024a (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/Kconfig | 1 | ||||
-rw-r--r-- | arch/sparc/include/asm/processor_64.h | 2 | ||||
-rw-r--r-- | arch/sparc/include/asm/ptrace.h | 3 | ||||
-rw-r--r-- | arch/sparc/kernel/process_64.c | 107 | ||||
-rw-r--r-- | arch/sparc/kernel/syscalls.S | 11 |
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 | ||
78 | config ARCH_DEFCONFIG | 79 | config 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 | ||
191 | extern pid_t kernel_thread(int (*fn)(void *), void * arg, unsigned long flags); | ||
192 | |||
193 | extern unsigned long get_wchan(struct task_struct *task); | 191 | extern 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 | |||
35 | struct global_reg_snapshot { | 38 | struct 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 | */ |
540 | int copy_thread(unsigned long clone_flags, unsigned long sp, | 540 | int 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 | */ | ||
620 | pid_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 | } | ||
649 | EXPORT_SYMBOL(kernel_thread); | ||
650 | |||
651 | typedef struct { | 604 | typedef 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: | |||
112 | ret_from_syscall: | 112 | ret_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 |