aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBrian Gerst <brgerst@gmail.com>2009-12-09 12:34:40 -0500
committerH. Peter Anvin <hpa@zytor.com>2009-12-10 18:55:26 -0500
commit3bd95dfb182969dc6d2a317c150e0df7107608d3 (patch)
tree8624969693d1bb51f06f85c35b7ac84ef41b9aeb
parentfc380ceed7fe469728ea4acdbda4495ea943ee1c (diff)
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>
-rw-r--r--arch/x86/kernel/entry_64.S49
-rw-r--r--arch/x86/kernel/process_64.c31
-rw-r--r--arch/x86/kernel/x8664_ksyms_64.c2
3 files changed, 32 insertions, 50 deletions
diff --git a/arch/x86/kernel/entry_64.S b/arch/x86/kernel/entry_64.S
index 63bca794c8f9..73d9b2c0e217 100644
--- a/arch/x86/kernel/entry_64.S
+++ b/arch/x86/kernel/entry_64.S
@@ -1166,63 +1166,20 @@ bad_gs:
1166 jmp 2b 1166 jmp 2b
1167 .previous 1167 .previous
1168 1168
1169/* 1169ENTRY(kernel_thread_helper)
1170 * Create a kernel thread.
1171 *
1172 * C extern interface:
1173 * extern long kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
1174 *
1175 * asm input arguments:
1176 * rdi: fn, rsi: arg, rdx: flags
1177 */
1178ENTRY(kernel_thread)
1179 CFI_STARTPROC
1180 FAKE_STACK_FRAME $child_rip
1181 SAVE_ALL
1182
1183 # rdi: flags, rsi: usp, rdx: will be &pt_regs
1184 movq %rdx,%rdi
1185 orq kernel_thread_flags(%rip),%rdi
1186 movq $-1, %rsi
1187 movq %rsp, %rdx
1188
1189 xorl %r8d,%r8d
1190 xorl %r9d,%r9d
1191
1192 # clone now
1193 call do_fork
1194 movq %rax,RAX(%rsp)
1195 xorl %edi,%edi
1196
1197 /*
1198 * It isn't worth to check for reschedule here,
1199 * so internally to the x86_64 port you can rely on kernel_thread()
1200 * not to reschedule the child before returning, this avoids the need
1201 * of hacks for example to fork off the per-CPU idle tasks.
1202 * [Hopefully no generic code relies on the reschedule -AK]
1203 */
1204 RESTORE_ALL
1205 UNFAKE_STACK_FRAME
1206 ret
1207 CFI_ENDPROC
1208END(kernel_thread)
1209
1210ENTRY(child_rip)
1211 pushq $0 # fake return address 1170 pushq $0 # fake return address
1212 CFI_STARTPROC 1171 CFI_STARTPROC
1213 /* 1172 /*
1214 * Here we are in the child and the registers are set as they were 1173 * Here we are in the child and the registers are set as they were
1215 * at kernel_thread() invocation in the parent. 1174 * at kernel_thread() invocation in the parent.
1216 */ 1175 */
1217 movq %rdi, %rax 1176 call *%rsi
1218 movq %rsi, %rdi
1219 call *%rax
1220 # exit 1177 # exit
1221 mov %eax, %edi 1178 mov %eax, %edi
1222 call do_exit 1179 call do_exit
1223 ud2 # padding for call trace 1180 ud2 # padding for call trace
1224 CFI_ENDPROC 1181 CFI_ENDPROC
1225END(child_rip) 1182END(kernel_thread_helper)
1226 1183
1227/* 1184/*
1228 * execve(). This function needs to use IRET, not SYSRET, to set up all state properly. 1185 * execve(). This function needs to use IRET, not SYSRET, to set up all state properly.
diff --git a/arch/x86/kernel/process_64.c b/arch/x86/kernel/process_64.c
index 83019f94b83d..92484c2130c6 100644
--- a/arch/x86/kernel/process_64.c
+++ b/arch/x86/kernel/process_64.c
@@ -59,8 +59,6 @@ asmlinkage extern void ret_from_fork(void);
59DEFINE_PER_CPU(unsigned long, old_rsp); 59DEFINE_PER_CPU(unsigned long, old_rsp);
60static DEFINE_PER_CPU(unsigned char, is_idle); 60static DEFINE_PER_CPU(unsigned char, is_idle);
61 61
62unsigned long kernel_thread_flags = CLONE_VM | CLONE_UNTRACED;
63
64static ATOMIC_NOTIFIER_HEAD(idle_notifier); 62static ATOMIC_NOTIFIER_HEAD(idle_notifier);
65 63
66void idle_notifier_register(struct notifier_block *n) 64void idle_notifier_register(struct notifier_block *n)
@@ -231,6 +229,35 @@ void show_regs(struct pt_regs *regs)
231 show_trace(NULL, regs, (void *)(regs + 1), regs->bp); 229 show_trace(NULL, regs, (void *)(regs + 1), regs->bp);
232} 230}
233 231
232/*
233 * This gets run with %si containing the
234 * function to call, and %di containing
235 * the "args".
236 */
237extern void kernel_thread_helper(void);
238
239/*
240 * Create a kernel thread
241 */
242int kernel_thread(int (*fn)(void *), void *arg, unsigned long flags)
243{
244 struct pt_regs regs;
245
246 memset(&regs, 0, sizeof(regs));
247
248 regs.si = (unsigned long) fn;
249 regs.di = (unsigned long) arg;
250
251 regs.orig_ax = -1;
252 regs.ip = (unsigned long) kernel_thread_helper;
253 regs.cs = __KERNEL_CS;
254 regs.flags = X86_EFLAGS_IF;
255
256 /* Ok, create the new process.. */
257 return do_fork(flags | CLONE_VM | CLONE_UNTRACED, ~0UL, &regs, 0, NULL, NULL);
258}
259EXPORT_SYMBOL(kernel_thread);
260
234void release_thread(struct task_struct *dead_task) 261void release_thread(struct task_struct *dead_task)
235{ 262{
236 if (dead_task->mm) { 263 if (dead_task->mm) {
diff --git a/arch/x86/kernel/x8664_ksyms_64.c b/arch/x86/kernel/x8664_ksyms_64.c
index a1029769b6f2..9fafaf83b3b8 100644
--- a/arch/x86/kernel/x8664_ksyms_64.c
+++ b/arch/x86/kernel/x8664_ksyms_64.c
@@ -17,8 +17,6 @@
17EXPORT_SYMBOL(mcount); 17EXPORT_SYMBOL(mcount);
18#endif 18#endif
19 19
20EXPORT_SYMBOL(kernel_thread);
21
22EXPORT_SYMBOL(__get_user_1); 20EXPORT_SYMBOL(__get_user_1);
23EXPORT_SYMBOL(__get_user_2); 21EXPORT_SYMBOL(__get_user_2);
24EXPORT_SYMBOL(__get_user_4); 22EXPORT_SYMBOL(__get_user_4);