diff options
author | Brian Gerst <brgerst@gmail.com> | 2009-12-09 12:34:40 -0500 |
---|---|---|
committer | H. Peter Anvin <hpa@zytor.com> | 2009-12-10 18:55:26 -0500 |
commit | 3bd95dfb182969dc6d2a317c150e0df7107608d3 (patch) | |
tree | 8624969693d1bb51f06f85c35b7ac84ef41b9aeb | |
parent | fc380ceed7fe469728ea4acdbda4495ea943ee1c (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.S | 49 | ||||
-rw-r--r-- | arch/x86/kernel/process_64.c | 31 | ||||
-rw-r--r-- | arch/x86/kernel/x8664_ksyms_64.c | 2 |
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 | /* | 1169 | ENTRY(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 | */ | ||
1178 | ENTRY(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 | ||
1208 | END(kernel_thread) | ||
1209 | |||
1210 | ENTRY(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 |
1225 | END(child_rip) | 1182 | END(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); | |||
59 | DEFINE_PER_CPU(unsigned long, old_rsp); | 59 | DEFINE_PER_CPU(unsigned long, old_rsp); |
60 | static DEFINE_PER_CPU(unsigned char, is_idle); | 60 | static DEFINE_PER_CPU(unsigned char, is_idle); |
61 | 61 | ||
62 | unsigned long kernel_thread_flags = CLONE_VM | CLONE_UNTRACED; | ||
63 | |||
64 | static ATOMIC_NOTIFIER_HEAD(idle_notifier); | 62 | static ATOMIC_NOTIFIER_HEAD(idle_notifier); |
65 | 63 | ||
66 | void idle_notifier_register(struct notifier_block *n) | 64 | void 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 | */ | ||
237 | extern void kernel_thread_helper(void); | ||
238 | |||
239 | /* | ||
240 | * Create a kernel thread | ||
241 | */ | ||
242 | int kernel_thread(int (*fn)(void *), void *arg, unsigned long flags) | ||
243 | { | ||
244 | struct pt_regs regs; | ||
245 | |||
246 | memset(®s, 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, ®s, 0, NULL, NULL); | ||
258 | } | ||
259 | EXPORT_SYMBOL(kernel_thread); | ||
260 | |||
234 | void release_thread(struct task_struct *dead_task) | 261 | void 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 @@ | |||
17 | EXPORT_SYMBOL(mcount); | 17 | EXPORT_SYMBOL(mcount); |
18 | #endif | 18 | #endif |
19 | 19 | ||
20 | EXPORT_SYMBOL(kernel_thread); | ||
21 | |||
22 | EXPORT_SYMBOL(__get_user_1); | 20 | EXPORT_SYMBOL(__get_user_1); |
23 | EXPORT_SYMBOL(__get_user_2); | 21 | EXPORT_SYMBOL(__get_user_2); |
24 | EXPORT_SYMBOL(__get_user_4); | 22 | EXPORT_SYMBOL(__get_user_4); |