diff options
Diffstat (limited to 'arch/x86_64/kernel/process.c')
-rw-r--r-- | arch/x86_64/kernel/process.c | 80 |
1 files changed, 76 insertions, 4 deletions
diff --git a/arch/x86_64/kernel/process.c b/arch/x86_64/kernel/process.c index 761b6d35e338..7577f9d7a75d 100644 --- a/arch/x86_64/kernel/process.c +++ b/arch/x86_64/kernel/process.c | |||
@@ -8,7 +8,8 @@ | |||
8 | * | 8 | * |
9 | * X86-64 port | 9 | * X86-64 port |
10 | * Andi Kleen. | 10 | * Andi Kleen. |
11 | * | 11 | * |
12 | * CPU hotplug support - ashok.raj@intel.com | ||
12 | * $Id: process.c,v 1.38 2002/01/15 10:08:03 ak Exp $ | 13 | * $Id: process.c,v 1.38 2002/01/15 10:08:03 ak Exp $ |
13 | */ | 14 | */ |
14 | 15 | ||
@@ -18,6 +19,7 @@ | |||
18 | 19 | ||
19 | #include <stdarg.h> | 20 | #include <stdarg.h> |
20 | 21 | ||
22 | #include <linux/cpu.h> | ||
21 | #include <linux/errno.h> | 23 | #include <linux/errno.h> |
22 | #include <linux/sched.h> | 24 | #include <linux/sched.h> |
23 | #include <linux/kernel.h> | 25 | #include <linux/kernel.h> |
@@ -34,6 +36,7 @@ | |||
34 | #include <linux/ptrace.h> | 36 | #include <linux/ptrace.h> |
35 | #include <linux/utsname.h> | 37 | #include <linux/utsname.h> |
36 | #include <linux/random.h> | 38 | #include <linux/random.h> |
39 | #include <linux/kprobes.h> | ||
37 | 40 | ||
38 | #include <asm/uaccess.h> | 41 | #include <asm/uaccess.h> |
39 | #include <asm/pgtable.h> | 42 | #include <asm/pgtable.h> |
@@ -153,6 +156,29 @@ void cpu_idle_wait(void) | |||
153 | } | 156 | } |
154 | EXPORT_SYMBOL_GPL(cpu_idle_wait); | 157 | EXPORT_SYMBOL_GPL(cpu_idle_wait); |
155 | 158 | ||
159 | #ifdef CONFIG_HOTPLUG_CPU | ||
160 | DECLARE_PER_CPU(int, cpu_state); | ||
161 | |||
162 | #include <asm/nmi.h> | ||
163 | /* We don't actually take CPU down, just spin without interrupts. */ | ||
164 | static inline void play_dead(void) | ||
165 | { | ||
166 | idle_task_exit(); | ||
167 | wbinvd(); | ||
168 | mb(); | ||
169 | /* Ack it */ | ||
170 | __get_cpu_var(cpu_state) = CPU_DEAD; | ||
171 | |||
172 | while (1) | ||
173 | safe_halt(); | ||
174 | } | ||
175 | #else | ||
176 | static inline void play_dead(void) | ||
177 | { | ||
178 | BUG(); | ||
179 | } | ||
180 | #endif /* CONFIG_HOTPLUG_CPU */ | ||
181 | |||
156 | /* | 182 | /* |
157 | * The idle thread. There's no useful work to be | 183 | * The idle thread. There's no useful work to be |
158 | * done, so just try to conserve power and have a | 184 | * done, so just try to conserve power and have a |
@@ -173,6 +199,8 @@ void cpu_idle (void) | |||
173 | idle = pm_idle; | 199 | idle = pm_idle; |
174 | if (!idle) | 200 | if (!idle) |
175 | idle = default_idle; | 201 | idle = default_idle; |
202 | if (cpu_is_offline(smp_processor_id())) | ||
203 | play_dead(); | ||
176 | idle(); | 204 | idle(); |
177 | } | 205 | } |
178 | 206 | ||
@@ -203,7 +231,7 @@ static void mwait_idle(void) | |||
203 | } | 231 | } |
204 | } | 232 | } |
205 | 233 | ||
206 | void __init select_idle_routine(const struct cpuinfo_x86 *c) | 234 | void __cpuinit select_idle_routine(const struct cpuinfo_x86 *c) |
207 | { | 235 | { |
208 | static int printed; | 236 | static int printed; |
209 | if (cpu_has(c, X86_FEATURE_MWAIT)) { | 237 | if (cpu_has(c, X86_FEATURE_MWAIT)) { |
@@ -293,6 +321,14 @@ void exit_thread(void) | |||
293 | { | 321 | { |
294 | struct task_struct *me = current; | 322 | struct task_struct *me = current; |
295 | struct thread_struct *t = &me->thread; | 323 | struct thread_struct *t = &me->thread; |
324 | |||
325 | /* | ||
326 | * Remove function-return probe instances associated with this task | ||
327 | * and put them back on the free list. Do not insert an exit probe for | ||
328 | * this function, it will be disabled by kprobe_flush_task if you do. | ||
329 | */ | ||
330 | kprobe_flush_task(me); | ||
331 | |||
296 | if (me->thread.io_bitmap_ptr) { | 332 | if (me->thread.io_bitmap_ptr) { |
297 | struct tss_struct *tss = &per_cpu(init_tss, get_cpu()); | 333 | struct tss_struct *tss = &per_cpu(init_tss, get_cpu()); |
298 | 334 | ||
@@ -312,6 +348,13 @@ void flush_thread(void) | |||
312 | struct task_struct *tsk = current; | 348 | struct task_struct *tsk = current; |
313 | struct thread_info *t = current_thread_info(); | 349 | struct thread_info *t = current_thread_info(); |
314 | 350 | ||
351 | /* | ||
352 | * Remove function-return probe instances associated with this task | ||
353 | * and put them back on the free list. Do not insert an exit probe for | ||
354 | * this function, it will be disabled by kprobe_flush_task if you do. | ||
355 | */ | ||
356 | kprobe_flush_task(tsk); | ||
357 | |||
315 | if (t->flags & _TIF_ABI_PENDING) | 358 | if (t->flags & _TIF_ABI_PENDING) |
316 | t->flags ^= (_TIF_ABI_PENDING | _TIF_IA32); | 359 | t->flags ^= (_TIF_ABI_PENDING | _TIF_IA32); |
317 | 360 | ||
@@ -439,6 +482,33 @@ out: | |||
439 | } | 482 | } |
440 | 483 | ||
441 | /* | 484 | /* |
485 | * This function selects if the context switch from prev to next | ||
486 | * has to tweak the TSC disable bit in the cr4. | ||
487 | */ | ||
488 | static inline void disable_tsc(struct task_struct *prev_p, | ||
489 | struct task_struct *next_p) | ||
490 | { | ||
491 | struct thread_info *prev, *next; | ||
492 | |||
493 | /* | ||
494 | * gcc should eliminate the ->thread_info dereference if | ||
495 | * has_secure_computing returns 0 at compile time (SECCOMP=n). | ||
496 | */ | ||
497 | prev = prev_p->thread_info; | ||
498 | next = next_p->thread_info; | ||
499 | |||
500 | if (has_secure_computing(prev) || has_secure_computing(next)) { | ||
501 | /* slow path here */ | ||
502 | if (has_secure_computing(prev) && | ||
503 | !has_secure_computing(next)) { | ||
504 | write_cr4(read_cr4() & ~X86_CR4_TSD); | ||
505 | } else if (!has_secure_computing(prev) && | ||
506 | has_secure_computing(next)) | ||
507 | write_cr4(read_cr4() | X86_CR4_TSD); | ||
508 | } | ||
509 | } | ||
510 | |||
511 | /* | ||
442 | * This special macro can be used to load a debugging register | 512 | * This special macro can be used to load a debugging register |
443 | */ | 513 | */ |
444 | #define loaddebug(thread,r) set_debug(thread->debugreg ## r, r) | 514 | #define loaddebug(thread,r) set_debug(thread->debugreg ## r, r) |
@@ -556,6 +626,8 @@ struct task_struct *__switch_to(struct task_struct *prev_p, struct task_struct * | |||
556 | } | 626 | } |
557 | } | 627 | } |
558 | 628 | ||
629 | disable_tsc(prev_p, next_p); | ||
630 | |||
559 | return prev_p; | 631 | return prev_p; |
560 | } | 632 | } |
561 | 633 | ||
@@ -656,7 +728,7 @@ long do_arch_prctl(struct task_struct *task, int code, unsigned long addr) | |||
656 | 728 | ||
657 | switch (code) { | 729 | switch (code) { |
658 | case ARCH_SET_GS: | 730 | case ARCH_SET_GS: |
659 | if (addr >= TASK_SIZE) | 731 | if (addr >= TASK_SIZE_OF(task)) |
660 | return -EPERM; | 732 | return -EPERM; |
661 | cpu = get_cpu(); | 733 | cpu = get_cpu(); |
662 | /* handle small bases via the GDT because that's faster to | 734 | /* handle small bases via the GDT because that's faster to |
@@ -682,7 +754,7 @@ long do_arch_prctl(struct task_struct *task, int code, unsigned long addr) | |||
682 | case ARCH_SET_FS: | 754 | case ARCH_SET_FS: |
683 | /* Not strictly needed for fs, but do it for symmetry | 755 | /* Not strictly needed for fs, but do it for symmetry |
684 | with gs */ | 756 | with gs */ |
685 | if (addr >= TASK_SIZE) | 757 | if (addr >= TASK_SIZE_OF(task)) |
686 | return -EPERM; | 758 | return -EPERM; |
687 | cpu = get_cpu(); | 759 | cpu = get_cpu(); |
688 | /* handle small bases via the GDT because that's faster to | 760 | /* handle small bases via the GDT because that's faster to |