Skip to content

Commit

Permalink
x86, 64-bit: Move kernel_thread to C
Browse files Browse the repository at this point in the history
Prepare for merging with 32-bit.

Signed-off-by: Brian Gerst <brgerst@gmail.com>
LKML-Reference: <1260380084-3707-2-git-send-email-brgerst@gmail.com>
Signed-off-by: H. Peter Anvin <hpa@zytor.com>
  • Loading branch information
Brian Gerst authored and H. Peter Anvin committed Dec 10, 2009
1 parent fc380ce commit 3bd95df
Show file tree
Hide file tree
Showing 3 changed files with 32 additions and 50 deletions.
49 changes: 3 additions & 46 deletions arch/x86/kernel/entry_64.S
Original file line number Diff line number Diff line change
Expand Up @@ -1166,63 +1166,20 @@ bad_gs:
jmp 2b
.previous

/*
* Create a kernel thread.
*
* C extern interface:
* extern long kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
*
* asm input arguments:
* rdi: fn, rsi: arg, rdx: flags
*/
ENTRY(kernel_thread)
CFI_STARTPROC
FAKE_STACK_FRAME $child_rip
SAVE_ALL

# rdi: flags, rsi: usp, rdx: will be &pt_regs
movq %rdx,%rdi
orq kernel_thread_flags(%rip),%rdi
movq $-1, %rsi
movq %rsp, %rdx

xorl %r8d,%r8d
xorl %r9d,%r9d

# clone now
call do_fork
movq %rax,RAX(%rsp)
xorl %edi,%edi

/*
* It isn't worth to check for reschedule here,
* so internally to the x86_64 port you can rely on kernel_thread()
* not to reschedule the child before returning, this avoids the need
* of hacks for example to fork off the per-CPU idle tasks.
* [Hopefully no generic code relies on the reschedule -AK]
*/
RESTORE_ALL
UNFAKE_STACK_FRAME
ret
CFI_ENDPROC
END(kernel_thread)

ENTRY(child_rip)
ENTRY(kernel_thread_helper)
pushq $0 # fake return address
CFI_STARTPROC
/*
* Here we are in the child and the registers are set as they were
* at kernel_thread() invocation in the parent.
*/
movq %rdi, %rax
movq %rsi, %rdi
call *%rax
call *%rsi
# exit
mov %eax, %edi
call do_exit
ud2 # padding for call trace
CFI_ENDPROC
END(child_rip)
END(kernel_thread_helper)

/*
* execve(). This function needs to use IRET, not SYSRET, to set up all state properly.
Expand Down
31 changes: 29 additions & 2 deletions arch/x86/kernel/process_64.c
Original file line number Diff line number Diff line change
Expand Up @@ -59,8 +59,6 @@ asmlinkage extern void ret_from_fork(void);
DEFINE_PER_CPU(unsigned long, old_rsp);
static DEFINE_PER_CPU(unsigned char, is_idle);

unsigned long kernel_thread_flags = CLONE_VM | CLONE_UNTRACED;

static ATOMIC_NOTIFIER_HEAD(idle_notifier);

void idle_notifier_register(struct notifier_block *n)
Expand Down Expand Up @@ -231,6 +229,35 @@ void show_regs(struct pt_regs *regs)
show_trace(NULL, regs, (void *)(regs + 1), regs->bp);
}

/*
* This gets run with %si containing the
* function to call, and %di containing
* the "args".
*/
extern void kernel_thread_helper(void);

/*
* Create a kernel thread
*/
int kernel_thread(int (*fn)(void *), void *arg, unsigned long flags)
{
struct pt_regs regs;

memset(&regs, 0, sizeof(regs));

regs.si = (unsigned long) fn;
regs.di = (unsigned long) arg;

regs.orig_ax = -1;
regs.ip = (unsigned long) kernel_thread_helper;
regs.cs = __KERNEL_CS;
regs.flags = X86_EFLAGS_IF;

/* Ok, create the new process.. */
return do_fork(flags | CLONE_VM | CLONE_UNTRACED, ~0UL, &regs, 0, NULL, NULL);
}
EXPORT_SYMBOL(kernel_thread);

void release_thread(struct task_struct *dead_task)
{
if (dead_task->mm) {
Expand Down
2 changes: 0 additions & 2 deletions arch/x86/kernel/x8664_ksyms_64.c
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,6 @@
EXPORT_SYMBOL(mcount);
#endif

EXPORT_SYMBOL(kernel_thread);

EXPORT_SYMBOL(__get_user_1);
EXPORT_SYMBOL(__get_user_2);
EXPORT_SYMBOL(__get_user_4);
Expand Down

0 comments on commit 3bd95df

Please sign in to comment.