diff options
Diffstat (limited to 'arch/i386/kernel/process.c')
-rw-r--r-- | arch/i386/kernel/process.c | 91 |
1 files changed, 41 insertions, 50 deletions
diff --git a/arch/i386/kernel/process.c b/arch/i386/kernel/process.c index 57d375900afb..99308510a17c 100644 --- a/arch/i386/kernel/process.c +++ b/arch/i386/kernel/process.c | |||
@@ -56,6 +56,7 @@ | |||
56 | 56 | ||
57 | #include <asm/tlbflush.h> | 57 | #include <asm/tlbflush.h> |
58 | #include <asm/cpu.h> | 58 | #include <asm/cpu.h> |
59 | #include <asm/pda.h> | ||
59 | 60 | ||
60 | asmlinkage void ret_from_fork(void) __asm__("ret_from_fork"); | 61 | asmlinkage void ret_from_fork(void) __asm__("ret_from_fork"); |
61 | 62 | ||
@@ -99,22 +100,18 @@ EXPORT_SYMBOL(enable_hlt); | |||
99 | */ | 100 | */ |
100 | void default_idle(void) | 101 | void default_idle(void) |
101 | { | 102 | { |
102 | local_irq_enable(); | ||
103 | |||
104 | if (!hlt_counter && boot_cpu_data.hlt_works_ok) { | 103 | if (!hlt_counter && boot_cpu_data.hlt_works_ok) { |
105 | current_thread_info()->status &= ~TS_POLLING; | 104 | current_thread_info()->status &= ~TS_POLLING; |
106 | smp_mb__after_clear_bit(); | 105 | smp_mb__after_clear_bit(); |
107 | while (!need_resched()) { | 106 | local_irq_disable(); |
108 | local_irq_disable(); | 107 | if (!need_resched()) |
109 | if (!need_resched()) | 108 | safe_halt(); /* enables interrupts racelessly */ |
110 | safe_halt(); | 109 | else |
111 | else | 110 | local_irq_enable(); |
112 | local_irq_enable(); | ||
113 | } | ||
114 | current_thread_info()->status |= TS_POLLING; | 111 | current_thread_info()->status |= TS_POLLING; |
115 | } else { | 112 | } else { |
116 | while (!need_resched()) | 113 | /* loop is done by the caller */ |
117 | cpu_relax(); | 114 | cpu_relax(); |
118 | } | 115 | } |
119 | } | 116 | } |
120 | #ifdef CONFIG_APM_MODULE | 117 | #ifdef CONFIG_APM_MODULE |
@@ -128,14 +125,7 @@ EXPORT_SYMBOL(default_idle); | |||
128 | */ | 125 | */ |
129 | static void poll_idle (void) | 126 | static void poll_idle (void) |
130 | { | 127 | { |
131 | local_irq_enable(); | 128 | cpu_relax(); |
132 | |||
133 | asm volatile( | ||
134 | "2:" | ||
135 | "testl %0, %1;" | ||
136 | "rep; nop;" | ||
137 | "je 2b;" | ||
138 | : : "i"(_TIF_NEED_RESCHED), "m" (current_thread_info()->flags)); | ||
139 | } | 129 | } |
140 | 130 | ||
141 | #ifdef CONFIG_HOTPLUG_CPU | 131 | #ifdef CONFIG_HOTPLUG_CPU |
@@ -205,7 +195,7 @@ void cpu_idle(void) | |||
205 | void cpu_idle_wait(void) | 195 | void cpu_idle_wait(void) |
206 | { | 196 | { |
207 | unsigned int cpu, this_cpu = get_cpu(); | 197 | unsigned int cpu, this_cpu = get_cpu(); |
208 | cpumask_t map; | 198 | cpumask_t map, tmp = current->cpus_allowed; |
209 | 199 | ||
210 | set_cpus_allowed(current, cpumask_of_cpu(this_cpu)); | 200 | set_cpus_allowed(current, cpumask_of_cpu(this_cpu)); |
211 | put_cpu(); | 201 | put_cpu(); |
@@ -227,6 +217,8 @@ void cpu_idle_wait(void) | |||
227 | } | 217 | } |
228 | cpus_and(map, map, cpu_online_map); | 218 | cpus_and(map, map, cpu_online_map); |
229 | } while (!cpus_empty(map)); | 219 | } while (!cpus_empty(map)); |
220 | |||
221 | set_cpus_allowed(current, tmp); | ||
230 | } | 222 | } |
231 | EXPORT_SYMBOL_GPL(cpu_idle_wait); | 223 | EXPORT_SYMBOL_GPL(cpu_idle_wait); |
232 | 224 | ||
@@ -254,8 +246,7 @@ void mwait_idle_with_hints(unsigned long eax, unsigned long ecx) | |||
254 | static void mwait_idle(void) | 246 | static void mwait_idle(void) |
255 | { | 247 | { |
256 | local_irq_enable(); | 248 | local_irq_enable(); |
257 | while (!need_resched()) | 249 | mwait_idle_with_hints(0, 0); |
258 | mwait_idle_with_hints(0, 0); | ||
259 | } | 250 | } |
260 | 251 | ||
261 | void __devinit select_idle_routine(const struct cpuinfo_x86 *c) | 252 | void __devinit select_idle_routine(const struct cpuinfo_x86 *c) |
@@ -312,8 +303,8 @@ void show_regs(struct pt_regs * regs) | |||
312 | regs->eax,regs->ebx,regs->ecx,regs->edx); | 303 | regs->eax,regs->ebx,regs->ecx,regs->edx); |
313 | printk("ESI: %08lx EDI: %08lx EBP: %08lx", | 304 | printk("ESI: %08lx EDI: %08lx EBP: %08lx", |
314 | regs->esi, regs->edi, regs->ebp); | 305 | regs->esi, regs->edi, regs->ebp); |
315 | printk(" DS: %04x ES: %04x\n", | 306 | printk(" DS: %04x ES: %04x GS: %04x\n", |
316 | 0xffff & regs->xds,0xffff & regs->xes); | 307 | 0xffff & regs->xds,0xffff & regs->xes, 0xffff & regs->xgs); |
317 | 308 | ||
318 | cr0 = read_cr0(); | 309 | cr0 = read_cr0(); |
319 | cr2 = read_cr2(); | 310 | cr2 = read_cr2(); |
@@ -336,7 +327,6 @@ extern void kernel_thread_helper(void); | |||
336 | int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags) | 327 | int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags) |
337 | { | 328 | { |
338 | struct pt_regs regs; | 329 | struct pt_regs regs; |
339 | int err; | ||
340 | 330 | ||
341 | memset(®s, 0, sizeof(regs)); | 331 | memset(®s, 0, sizeof(regs)); |
342 | 332 | ||
@@ -345,16 +335,14 @@ int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags) | |||
345 | 335 | ||
346 | regs.xds = __USER_DS; | 336 | regs.xds = __USER_DS; |
347 | regs.xes = __USER_DS; | 337 | regs.xes = __USER_DS; |
338 | regs.xgs = __KERNEL_PDA; | ||
348 | regs.orig_eax = -1; | 339 | regs.orig_eax = -1; |
349 | regs.eip = (unsigned long) kernel_thread_helper; | 340 | regs.eip = (unsigned long) kernel_thread_helper; |
350 | regs.xcs = __KERNEL_CS | get_kernel_rpl(); | 341 | regs.xcs = __KERNEL_CS | get_kernel_rpl(); |
351 | regs.eflags = X86_EFLAGS_IF | X86_EFLAGS_SF | X86_EFLAGS_PF | 0x2; | 342 | regs.eflags = X86_EFLAGS_IF | X86_EFLAGS_SF | X86_EFLAGS_PF | 0x2; |
352 | 343 | ||
353 | /* Ok, create the new process.. */ | 344 | /* Ok, create the new process.. */ |
354 | err = do_fork(flags | CLONE_VM | CLONE_UNTRACED, 0, ®s, 0, NULL, NULL); | 345 | return do_fork(flags | CLONE_VM | CLONE_UNTRACED, 0, ®s, 0, NULL, NULL); |
355 | if (err == 0) /* terminate kernel stack */ | ||
356 | task_pt_regs(current)->eip = 0; | ||
357 | return err; | ||
358 | } | 346 | } |
359 | EXPORT_SYMBOL(kernel_thread); | 347 | EXPORT_SYMBOL(kernel_thread); |
360 | 348 | ||
@@ -433,7 +421,6 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long esp, | |||
433 | p->thread.eip = (unsigned long) ret_from_fork; | 421 | p->thread.eip = (unsigned long) ret_from_fork; |
434 | 422 | ||
435 | savesegment(fs,p->thread.fs); | 423 | savesegment(fs,p->thread.fs); |
436 | savesegment(gs,p->thread.gs); | ||
437 | 424 | ||
438 | tsk = current; | 425 | tsk = current; |
439 | if (unlikely(test_tsk_thread_flag(tsk, TIF_IO_BITMAP))) { | 426 | if (unlikely(test_tsk_thread_flag(tsk, TIF_IO_BITMAP))) { |
@@ -510,7 +497,7 @@ void dump_thread(struct pt_regs * regs, struct user * dump) | |||
510 | dump->regs.ds = regs->xds; | 497 | dump->regs.ds = regs->xds; |
511 | dump->regs.es = regs->xes; | 498 | dump->regs.es = regs->xes; |
512 | savesegment(fs,dump->regs.fs); | 499 | savesegment(fs,dump->regs.fs); |
513 | savesegment(gs,dump->regs.gs); | 500 | dump->regs.gs = regs->xgs; |
514 | dump->regs.orig_eax = regs->orig_eax; | 501 | dump->regs.orig_eax = regs->orig_eax; |
515 | dump->regs.eip = regs->eip; | 502 | dump->regs.eip = regs->eip; |
516 | dump->regs.cs = regs->xcs; | 503 | dump->regs.cs = regs->xcs; |
@@ -650,22 +637,27 @@ struct task_struct fastcall * __switch_to(struct task_struct *prev_p, struct tas | |||
650 | 637 | ||
651 | __unlazy_fpu(prev_p); | 638 | __unlazy_fpu(prev_p); |
652 | 639 | ||
640 | |||
641 | /* we're going to use this soon, after a few expensive things */ | ||
642 | if (next_p->fpu_counter > 5) | ||
643 | prefetch(&next->i387.fxsave); | ||
644 | |||
653 | /* | 645 | /* |
654 | * Reload esp0. | 646 | * Reload esp0. |
655 | */ | 647 | */ |
656 | load_esp0(tss, next); | 648 | load_esp0(tss, next); |
657 | 649 | ||
658 | /* | 650 | /* |
659 | * Save away %fs and %gs. No need to save %es and %ds, as | 651 | * Save away %fs. No need to save %gs, as it was saved on the |
660 | * those are always kernel segments while inside the kernel. | 652 | * stack on entry. No need to save %es and %ds, as those are |
661 | * Doing this before setting the new TLS descriptors avoids | 653 | * always kernel segments while inside the kernel. Doing this |
662 | * the situation where we temporarily have non-reloadable | 654 | * before setting the new TLS descriptors avoids the situation |
663 | * segments in %fs and %gs. This could be an issue if the | 655 | * where we temporarily have non-reloadable segments in %fs |
664 | * NMI handler ever used %fs or %gs (it does not today), or | 656 | * and %gs. This could be an issue if the NMI handler ever |
665 | * if the kernel is running inside of a hypervisor layer. | 657 | * used %fs or %gs (it does not today), or if the kernel is |
658 | * running inside of a hypervisor layer. | ||
666 | */ | 659 | */ |
667 | savesegment(fs, prev->fs); | 660 | savesegment(fs, prev->fs); |
668 | savesegment(gs, prev->gs); | ||
669 | 661 | ||
670 | /* | 662 | /* |
671 | * Load the per-thread Thread-Local Storage descriptor. | 663 | * Load the per-thread Thread-Local Storage descriptor. |
@@ -673,22 +665,14 @@ struct task_struct fastcall * __switch_to(struct task_struct *prev_p, struct tas | |||
673 | load_TLS(next, cpu); | 665 | load_TLS(next, cpu); |
674 | 666 | ||
675 | /* | 667 | /* |
676 | * Restore %fs and %gs if needed. | 668 | * Restore %fs if needed. |
677 | * | 669 | * |
678 | * Glibc normally makes %fs be zero, and %gs is one of | 670 | * Glibc normally makes %fs be zero. |
679 | * the TLS segments. | ||
680 | */ | 671 | */ |
681 | if (unlikely(prev->fs | next->fs)) | 672 | if (unlikely(prev->fs | next->fs)) |
682 | loadsegment(fs, next->fs); | 673 | loadsegment(fs, next->fs); |
683 | 674 | ||
684 | if (prev->gs | next->gs) | 675 | write_pda(pcurrent, next_p); |
685 | loadsegment(gs, next->gs); | ||
686 | |||
687 | /* | ||
688 | * Restore IOPL if needed. | ||
689 | */ | ||
690 | if (unlikely(prev->iopl != next->iopl)) | ||
691 | set_iopl_mask(next->iopl); | ||
692 | 676 | ||
693 | /* | 677 | /* |
694 | * Now maybe handle debug registers and/or IO bitmaps | 678 | * Now maybe handle debug registers and/or IO bitmaps |
@@ -699,6 +683,13 @@ struct task_struct fastcall * __switch_to(struct task_struct *prev_p, struct tas | |||
699 | 683 | ||
700 | disable_tsc(prev_p, next_p); | 684 | disable_tsc(prev_p, next_p); |
701 | 685 | ||
686 | /* If the task has used fpu the last 5 timeslices, just do a full | ||
687 | * restore of the math state immediately to avoid the trap; the | ||
688 | * chances of needing FPU soon are obviously high now | ||
689 | */ | ||
690 | if (next_p->fpu_counter > 5) | ||
691 | math_state_restore(); | ||
692 | |||
702 | return prev_p; | 693 | return prev_p; |
703 | } | 694 | } |
704 | 695 | ||