sparc64: switch to generic kernel_thread()
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
This commit is contained in:
parent
dff933da76
commit
1918c7f548
|
@ -74,6 +74,7 @@ config SPARC64
|
||||||
select ARCH_HAVE_NMI_SAFE_CMPXCHG
|
select ARCH_HAVE_NMI_SAFE_CMPXCHG
|
||||||
select HAVE_C_RECORDMCOUNT
|
select HAVE_C_RECORDMCOUNT
|
||||||
select NO_BOOTMEM
|
select NO_BOOTMEM
|
||||||
|
select GENERIC_KERNEL_THREAD
|
||||||
|
|
||||||
config ARCH_DEFCONFIG
|
config ARCH_DEFCONFIG
|
||||||
string
|
string
|
||||||
|
|
|
@ -188,8 +188,6 @@ do { \
|
||||||
/* Free all resources held by a thread. */
|
/* Free all resources held by a thread. */
|
||||||
#define release_thread(tsk) do { } while (0)
|
#define release_thread(tsk) do { } while (0)
|
||||||
|
|
||||||
extern pid_t kernel_thread(int (*fn)(void *), void * arg, unsigned long flags);
|
|
||||||
|
|
||||||
extern unsigned long get_wchan(struct task_struct *task);
|
extern unsigned long get_wchan(struct task_struct *task);
|
||||||
|
|
||||||
#define task_pt_regs(tsk) (task_thread_info(tsk)->kregs)
|
#define task_pt_regs(tsk) (task_thread_info(tsk)->kregs)
|
||||||
|
|
|
@ -32,6 +32,9 @@ static inline bool pt_regs_clear_syscall(struct pt_regs *regs)
|
||||||
#define arch_ptrace_stop(exit_code, info) \
|
#define arch_ptrace_stop(exit_code, info) \
|
||||||
synchronize_user_stack()
|
synchronize_user_stack()
|
||||||
|
|
||||||
|
#define current_pt_regs() \
|
||||||
|
((struct pt_regs *)((unsigned long)current_thread_info() + THREAD_SIZE) - 1)
|
||||||
|
|
||||||
struct global_reg_snapshot {
|
struct global_reg_snapshot {
|
||||||
unsigned long tstate;
|
unsigned long tstate;
|
||||||
unsigned long tpc;
|
unsigned long tpc;
|
||||||
|
|
|
@ -538,64 +538,56 @@ asmlinkage long sparc_do_fork(unsigned long clone_flags,
|
||||||
* Child --> %o0 == parents pid, %o1 == 1
|
* Child --> %o0 == parents pid, %o1 == 1
|
||||||
*/
|
*/
|
||||||
int copy_thread(unsigned long clone_flags, unsigned long sp,
|
int copy_thread(unsigned long clone_flags, unsigned long sp,
|
||||||
unsigned long unused,
|
unsigned long arg,
|
||||||
struct task_struct *p, struct pt_regs *regs)
|
struct task_struct *p, struct pt_regs *regs)
|
||||||
{
|
{
|
||||||
struct thread_info *t = task_thread_info(p);
|
struct thread_info *t = task_thread_info(p);
|
||||||
struct sparc_stackf *parent_sf;
|
struct sparc_stackf *parent_sf;
|
||||||
unsigned long child_stack_sz;
|
unsigned long child_stack_sz;
|
||||||
char *child_trap_frame;
|
char *child_trap_frame;
|
||||||
int kernel_thread;
|
|
||||||
|
|
||||||
kernel_thread = (regs->tstate & TSTATE_PRIV) ? 1 : 0;
|
|
||||||
parent_sf = ((struct sparc_stackf *) regs) - 1;
|
|
||||||
|
|
||||||
/* Calculate offset to stack_frame & pt_regs */
|
/* Calculate offset to stack_frame & pt_regs */
|
||||||
child_stack_sz = ((STACKFRAME_SZ + TRACEREG_SZ) +
|
child_stack_sz = (STACKFRAME_SZ + TRACEREG_SZ);
|
||||||
(kernel_thread ? STACKFRAME_SZ : 0));
|
|
||||||
child_trap_frame = (task_stack_page(p) +
|
child_trap_frame = (task_stack_page(p) +
|
||||||
(THREAD_SIZE - child_stack_sz));
|
(THREAD_SIZE - child_stack_sz));
|
||||||
memcpy(child_trap_frame, parent_sf, child_stack_sz);
|
|
||||||
|
|
||||||
__thread_flag_byte_ptr(t)[TI_FLAG_BYTE_CWP] =
|
|
||||||
(regs->tstate + 1) & TSTATE_CWP;
|
|
||||||
t->new_child = 1;
|
t->new_child = 1;
|
||||||
t->ksp = ((unsigned long) child_trap_frame) - STACK_BIAS;
|
t->ksp = ((unsigned long) child_trap_frame) - STACK_BIAS;
|
||||||
t->kregs = (struct pt_regs *) (child_trap_frame +
|
t->kregs = (struct pt_regs *) (child_trap_frame +
|
||||||
sizeof(struct sparc_stackf));
|
sizeof(struct sparc_stackf));
|
||||||
t->fpsaved[0] = 0;
|
t->fpsaved[0] = 0;
|
||||||
|
|
||||||
if (kernel_thread) {
|
if (unlikely(p->flags & PF_KTHREAD)) {
|
||||||
struct sparc_stackf *child_sf = (struct sparc_stackf *)
|
memset(child_trap_frame, 0, child_stack_sz);
|
||||||
(child_trap_frame + (STACKFRAME_SZ + TRACEREG_SZ));
|
__thread_flag_byte_ptr(t)[TI_FLAG_BYTE_CWP] =
|
||||||
|
(current_pt_regs()->tstate + 1) & TSTATE_CWP;
|
||||||
/* Zero terminate the stack backtrace. */
|
|
||||||
child_sf->fp = NULL;
|
|
||||||
t->kregs->u_regs[UREG_FP] =
|
|
||||||
((unsigned long) child_sf) - STACK_BIAS;
|
|
||||||
|
|
||||||
t->current_ds = ASI_P;
|
t->current_ds = ASI_P;
|
||||||
t->kregs->u_regs[UREG_G6] = (unsigned long) t;
|
t->kregs->u_regs[UREG_G1] = sp; /* function */
|
||||||
t->kregs->u_regs[UREG_G4] = (unsigned long) t->task;
|
t->kregs->u_regs[UREG_G2] = arg;
|
||||||
} else {
|
return 0;
|
||||||
if (t->flags & _TIF_32BIT) {
|
|
||||||
sp &= 0x00000000ffffffffUL;
|
|
||||||
regs->u_regs[UREG_FP] &= 0x00000000ffffffffUL;
|
|
||||||
}
|
|
||||||
t->kregs->u_regs[UREG_FP] = sp;
|
|
||||||
t->current_ds = ASI_AIUS;
|
|
||||||
if (sp != regs->u_regs[UREG_FP]) {
|
|
||||||
unsigned long csp;
|
|
||||||
|
|
||||||
csp = clone_stackframe(sp, regs->u_regs[UREG_FP]);
|
|
||||||
if (!csp)
|
|
||||||
return -EFAULT;
|
|
||||||
t->kregs->u_regs[UREG_FP] = csp;
|
|
||||||
}
|
|
||||||
if (t->utraps)
|
|
||||||
t->utraps[0]++;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
parent_sf = ((struct sparc_stackf *) regs) - 1;
|
||||||
|
memcpy(child_trap_frame, parent_sf, child_stack_sz);
|
||||||
|
if (t->flags & _TIF_32BIT) {
|
||||||
|
sp &= 0x00000000ffffffffUL;
|
||||||
|
regs->u_regs[UREG_FP] &= 0x00000000ffffffffUL;
|
||||||
|
}
|
||||||
|
t->kregs->u_regs[UREG_FP] = sp;
|
||||||
|
__thread_flag_byte_ptr(t)[TI_FLAG_BYTE_CWP] =
|
||||||
|
(regs->tstate + 1) & TSTATE_CWP;
|
||||||
|
t->current_ds = ASI_AIUS;
|
||||||
|
if (sp != regs->u_regs[UREG_FP]) {
|
||||||
|
unsigned long csp;
|
||||||
|
|
||||||
|
csp = clone_stackframe(sp, regs->u_regs[UREG_FP]);
|
||||||
|
if (!csp)
|
||||||
|
return -EFAULT;
|
||||||
|
t->kregs->u_regs[UREG_FP] = csp;
|
||||||
|
}
|
||||||
|
if (t->utraps)
|
||||||
|
t->utraps[0]++;
|
||||||
|
|
||||||
/* Set the return value for the child. */
|
/* Set the return value for the child. */
|
||||||
t->kregs->u_regs[UREG_I0] = current->pid;
|
t->kregs->u_regs[UREG_I0] = current->pid;
|
||||||
t->kregs->u_regs[UREG_I1] = 1;
|
t->kregs->u_regs[UREG_I1] = 1;
|
||||||
|
@ -609,45 +601,6 @@ int copy_thread(unsigned long clone_flags, unsigned long sp,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* This is the mechanism for creating a new kernel thread.
|
|
||||||
*
|
|
||||||
* NOTE! Only a kernel-only process(ie the swapper or direct descendants
|
|
||||||
* who haven't done an "execve()") should use this: it will work within
|
|
||||||
* a system call from a "real" process, but the process memory space will
|
|
||||||
* not be freed until both the parent and the child have exited.
|
|
||||||
*/
|
|
||||||
pid_t kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
|
|
||||||
{
|
|
||||||
long retval;
|
|
||||||
|
|
||||||
/* If the parent runs before fn(arg) is called by the child,
|
|
||||||
* the input registers of this function can be clobbered.
|
|
||||||
* So we stash 'fn' and 'arg' into global registers which
|
|
||||||
* will not be modified by the parent.
|
|
||||||
*/
|
|
||||||
__asm__ __volatile__("mov %4, %%g2\n\t" /* Save FN into global */
|
|
||||||
"mov %5, %%g3\n\t" /* Save ARG into global */
|
|
||||||
"mov %1, %%g1\n\t" /* Clone syscall nr. */
|
|
||||||
"mov %2, %%o0\n\t" /* Clone flags. */
|
|
||||||
"mov 0, %%o1\n\t" /* usp arg == 0 */
|
|
||||||
"t 0x6d\n\t" /* Linux/Sparc clone(). */
|
|
||||||
"brz,a,pn %%o1, 1f\n\t" /* Parent, just return. */
|
|
||||||
" mov %%o0, %0\n\t"
|
|
||||||
"jmpl %%g2, %%o7\n\t" /* Call the function. */
|
|
||||||
" mov %%g3, %%o0\n\t" /* Set arg in delay. */
|
|
||||||
"mov %3, %%g1\n\t"
|
|
||||||
"t 0x6d\n\t" /* Linux/Sparc exit(). */
|
|
||||||
/* Notreached by child. */
|
|
||||||
"1:" :
|
|
||||||
"=r" (retval) :
|
|
||||||
"i" (__NR_clone), "r" (flags | CLONE_VM | CLONE_UNTRACED),
|
|
||||||
"i" (__NR_exit), "r" (fn), "r" (arg) :
|
|
||||||
"g1", "g2", "g3", "o0", "o1", "memory", "cc");
|
|
||||||
return retval;
|
|
||||||
}
|
|
||||||
EXPORT_SYMBOL(kernel_thread);
|
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
union {
|
union {
|
||||||
unsigned int pr_regs[32];
|
unsigned int pr_regs[32];
|
||||||
|
|
|
@ -112,11 +112,16 @@ sys_clone:
|
||||||
ret_from_syscall:
|
ret_from_syscall:
|
||||||
/* Clear current_thread_info()->new_child. */
|
/* Clear current_thread_info()->new_child. */
|
||||||
stb %g0, [%g6 + TI_NEW_CHILD]
|
stb %g0, [%g6 + TI_NEW_CHILD]
|
||||||
ldx [%g6 + TI_FLAGS], %l0
|
|
||||||
call schedule_tail
|
call schedule_tail
|
||||||
mov %g7, %o0
|
mov %g7, %o0
|
||||||
ba,pt %xcc, ret_sys_call
|
ldx [%sp + PTREGS_OFF + PT_V9_I0], %o0
|
||||||
ldx [%sp + PTREGS_OFF + PT_V9_I0], %o0
|
brnz,a,pt %o0, ret_sys_call
|
||||||
|
ldx [%g6 + TI_FLAGS], %l0
|
||||||
|
ldx [%sp + PTREGS_OFF + PT_V9_G1], %l0
|
||||||
|
call %l0
|
||||||
|
ldx [%sp + PTREGS_OFF + PT_V9_G2], %o0
|
||||||
|
call do_exit ! will not return
|
||||||
|
mov 0,%o0
|
||||||
|
|
||||||
.globl sparc_exit
|
.globl sparc_exit
|
||||||
.type sparc_exit,#function
|
.type sparc_exit,#function
|
||||||
|
|
Loading…
Reference in New Issue