diff options
Diffstat (limited to 'arch/i386/kernel/process.c')
-rw-r--r-- | arch/i386/kernel/process.c | 81 |
1 files changed, 37 insertions, 44 deletions
diff --git a/arch/i386/kernel/process.c b/arch/i386/kernel/process.c index dd53c58f64f1..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 |
@@ -256,8 +246,7 @@ void mwait_idle_with_hints(unsigned long eax, unsigned long ecx) | |||
256 | static void mwait_idle(void) | 246 | static void mwait_idle(void) |
257 | { | 247 | { |
258 | local_irq_enable(); | 248 | local_irq_enable(); |
259 | while (!need_resched()) | 249 | mwait_idle_with_hints(0, 0); |
260 | mwait_idle_with_hints(0, 0); | ||
261 | } | 250 | } |
262 | 251 | ||
263 | void __devinit select_idle_routine(const struct cpuinfo_x86 *c) | 252 | void __devinit select_idle_routine(const struct cpuinfo_x86 *c) |
@@ -314,8 +303,8 @@ void show_regs(struct pt_regs * regs) | |||
314 | regs->eax,regs->ebx,regs->ecx,regs->edx); | 303 | regs->eax,regs->ebx,regs->ecx,regs->edx); |
315 | printk("ESI: %08lx EDI: %08lx EBP: %08lx", | 304 | printk("ESI: %08lx EDI: %08lx EBP: %08lx", |
316 | regs->esi, regs->edi, regs->ebp); | 305 | regs->esi, regs->edi, regs->ebp); |
317 | printk(" DS: %04x ES: %04x\n", | 306 | printk(" DS: %04x ES: %04x GS: %04x\n", |
318 | 0xffff & regs->xds,0xffff & regs->xes); | 307 | 0xffff & regs->xds,0xffff & regs->xes, 0xffff & regs->xgs); |
319 | 308 | ||
320 | cr0 = read_cr0(); | 309 | cr0 = read_cr0(); |
321 | cr2 = read_cr2(); | 310 | cr2 = read_cr2(); |
@@ -346,6 +335,7 @@ int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags) | |||
346 | 335 | ||
347 | regs.xds = __USER_DS; | 336 | regs.xds = __USER_DS; |
348 | regs.xes = __USER_DS; | 337 | regs.xes = __USER_DS; |
338 | regs.xgs = __KERNEL_PDA; | ||
349 | regs.orig_eax = -1; | 339 | regs.orig_eax = -1; |
350 | regs.eip = (unsigned long) kernel_thread_helper; | 340 | regs.eip = (unsigned long) kernel_thread_helper; |
351 | regs.xcs = __KERNEL_CS | get_kernel_rpl(); | 341 | regs.xcs = __KERNEL_CS | get_kernel_rpl(); |
@@ -431,7 +421,6 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long esp, | |||
431 | p->thread.eip = (unsigned long) ret_from_fork; | 421 | p->thread.eip = (unsigned long) ret_from_fork; |
432 | 422 | ||
433 | savesegment(fs,p->thread.fs); | 423 | savesegment(fs,p->thread.fs); |
434 | savesegment(gs,p->thread.gs); | ||
435 | 424 | ||
436 | tsk = current; | 425 | tsk = current; |
437 | if (unlikely(test_tsk_thread_flag(tsk, TIF_IO_BITMAP))) { | 426 | if (unlikely(test_tsk_thread_flag(tsk, TIF_IO_BITMAP))) { |
@@ -508,7 +497,7 @@ void dump_thread(struct pt_regs * regs, struct user * dump) | |||
508 | dump->regs.ds = regs->xds; | 497 | dump->regs.ds = regs->xds; |
509 | dump->regs.es = regs->xes; | 498 | dump->regs.es = regs->xes; |
510 | savesegment(fs,dump->regs.fs); | 499 | savesegment(fs,dump->regs.fs); |
511 | savesegment(gs,dump->regs.gs); | 500 | dump->regs.gs = regs->xgs; |
512 | dump->regs.orig_eax = regs->orig_eax; | 501 | dump->regs.orig_eax = regs->orig_eax; |
513 | dump->regs.eip = regs->eip; | 502 | dump->regs.eip = regs->eip; |
514 | dump->regs.cs = regs->xcs; | 503 | dump->regs.cs = regs->xcs; |
@@ -648,22 +637,27 @@ struct task_struct fastcall * __switch_to(struct task_struct *prev_p, struct tas | |||
648 | 637 | ||
649 | __unlazy_fpu(prev_p); | 638 | __unlazy_fpu(prev_p); |
650 | 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 | |||
651 | /* | 645 | /* |
652 | * Reload esp0. | 646 | * Reload esp0. |
653 | */ | 647 | */ |
654 | load_esp0(tss, next); | 648 | load_esp0(tss, next); |
655 | 649 | ||
656 | /* | 650 | /* |
657 | * 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 |
658 | * those are always kernel segments while inside the kernel. | 652 | * stack on entry. No need to save %es and %ds, as those are |
659 | * Doing this before setting the new TLS descriptors avoids | 653 | * always kernel segments while inside the kernel. Doing this |
660 | * the situation where we temporarily have non-reloadable | 654 | * before setting the new TLS descriptors avoids the situation |
661 | * segments in %fs and %gs. This could be an issue if the | 655 | * where we temporarily have non-reloadable segments in %fs |
662 | * 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 |
663 | * 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. | ||
664 | */ | 659 | */ |
665 | savesegment(fs, prev->fs); | 660 | savesegment(fs, prev->fs); |
666 | savesegment(gs, prev->gs); | ||
667 | 661 | ||
668 | /* | 662 | /* |
669 | * Load the per-thread Thread-Local Storage descriptor. | 663 | * Load the per-thread Thread-Local Storage descriptor. |
@@ -671,22 +665,14 @@ struct task_struct fastcall * __switch_to(struct task_struct *prev_p, struct tas | |||
671 | load_TLS(next, cpu); | 665 | load_TLS(next, cpu); |
672 | 666 | ||
673 | /* | 667 | /* |
674 | * Restore %fs and %gs if needed. | 668 | * Restore %fs if needed. |
675 | * | 669 | * |
676 | * Glibc normally makes %fs be zero, and %gs is one of | 670 | * Glibc normally makes %fs be zero. |
677 | * the TLS segments. | ||
678 | */ | 671 | */ |
679 | if (unlikely(prev->fs | next->fs)) | 672 | if (unlikely(prev->fs | next->fs)) |
680 | loadsegment(fs, next->fs); | 673 | loadsegment(fs, next->fs); |
681 | 674 | ||
682 | if (prev->gs | next->gs) | 675 | write_pda(pcurrent, next_p); |
683 | loadsegment(gs, next->gs); | ||
684 | |||
685 | /* | ||
686 | * Restore IOPL if needed. | ||
687 | */ | ||
688 | if (unlikely(prev->iopl != next->iopl)) | ||
689 | set_iopl_mask(next->iopl); | ||
690 | 676 | ||
691 | /* | 677 | /* |
692 | * Now maybe handle debug registers and/or IO bitmaps | 678 | * Now maybe handle debug registers and/or IO bitmaps |
@@ -697,6 +683,13 @@ struct task_struct fastcall * __switch_to(struct task_struct *prev_p, struct tas | |||
697 | 683 | ||
698 | disable_tsc(prev_p, next_p); | 684 | disable_tsc(prev_p, next_p); |
699 | 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 | |||
700 | return prev_p; | 693 | return prev_p; |
701 | } | 694 | } |
702 | 695 | ||