x86, 64-bit: Move kernel_thread to C
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>
This commit is contained in:
committed by
H. Peter Anvin
parent
fc380ceed7
commit
3bd95dfb18
@@ -1166,63 +1166,20 @@ bad_gs:
|
|||||||
jmp 2b
|
jmp 2b
|
||||||
.previous
|
.previous
|
||||||
|
|
||||||
/*
|
ENTRY(kernel_thread_helper)
|
||||||
* 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)
|
|
||||||
pushq $0 # fake return address
|
pushq $0 # fake return address
|
||||||
CFI_STARTPROC
|
CFI_STARTPROC
|
||||||
/*
|
/*
|
||||||
* Here we are in the child and the registers are set as they were
|
* Here we are in the child and the registers are set as they were
|
||||||
* at kernel_thread() invocation in the parent.
|
* at kernel_thread() invocation in the parent.
|
||||||
*/
|
*/
|
||||||
movq %rdi, %rax
|
call *%rsi
|
||||||
movq %rsi, %rdi
|
|
||||||
call *%rax
|
|
||||||
# exit
|
# exit
|
||||||
mov %eax, %edi
|
mov %eax, %edi
|
||||||
call do_exit
|
call do_exit
|
||||||
ud2 # padding for call trace
|
ud2 # padding for call trace
|
||||||
CFI_ENDPROC
|
CFI_ENDPROC
|
||||||
END(child_rip)
|
END(kernel_thread_helper)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* execve(). This function needs to use IRET, not SYSRET, to set up all state properly.
|
* execve(). This function needs to use IRET, not SYSRET, to set up all state properly.
|
||||||
|
@@ -59,8 +59,6 @@ asmlinkage extern void ret_from_fork(void);
|
|||||||
DEFINE_PER_CPU(unsigned long, old_rsp);
|
DEFINE_PER_CPU(unsigned long, old_rsp);
|
||||||
static DEFINE_PER_CPU(unsigned char, is_idle);
|
static DEFINE_PER_CPU(unsigned char, is_idle);
|
||||||
|
|
||||||
unsigned long kernel_thread_flags = CLONE_VM | CLONE_UNTRACED;
|
|
||||||
|
|
||||||
static ATOMIC_NOTIFIER_HEAD(idle_notifier);
|
static ATOMIC_NOTIFIER_HEAD(idle_notifier);
|
||||||
|
|
||||||
void idle_notifier_register(struct notifier_block *n)
|
void idle_notifier_register(struct notifier_block *n)
|
||||||
@@ -231,6 +229,35 @@ void show_regs(struct pt_regs *regs)
|
|||||||
show_trace(NULL, regs, (void *)(regs + 1), regs->bp);
|
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(®s, 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, ®s, 0, NULL, NULL);
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL(kernel_thread);
|
||||||
|
|
||||||
void release_thread(struct task_struct *dead_task)
|
void release_thread(struct task_struct *dead_task)
|
||||||
{
|
{
|
||||||
if (dead_task->mm) {
|
if (dead_task->mm) {
|
||||||
|
@@ -17,8 +17,6 @@
|
|||||||
EXPORT_SYMBOL(mcount);
|
EXPORT_SYMBOL(mcount);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
EXPORT_SYMBOL(kernel_thread);
|
|
||||||
|
|
||||||
EXPORT_SYMBOL(__get_user_1);
|
EXPORT_SYMBOL(__get_user_1);
|
||||||
EXPORT_SYMBOL(__get_user_2);
|
EXPORT_SYMBOL(__get_user_2);
|
||||||
EXPORT_SYMBOL(__get_user_4);
|
EXPORT_SYMBOL(__get_user_4);
|
||||||
|
Reference in New Issue
Block a user