[PATCH] [11/66] x86_64: save FPU context slightly later

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



From: Jan Beulich <jbeulich@xxxxxxxxxx>
Touching of the floating point state in a kernel debugger must be
NMI-safe, specifically math_state_restore() must be able to deal with
being called out of an NMI context. In order to do that reliably, the
context switch code must take care to not leave a window open where
the current task's TS_USEDFPU flag and CR0.TS could get out of sync.

Signed-Off-By: Jan Beulich <jbeulich@xxxxxxxxxx>

Signed-off-by: Andi Kleen <ak@xxxxxxx>

 arch/x86_64/kernel/pmtimer.c |    3 ++-
 arch/x86_64/kernel/process.c |   17 ++++++++++++++---
 2 files changed, 16 insertions(+), 4 deletions(-)

Index: linux/arch/x86_64/kernel/process.c
===================================================================
--- linux.orig/arch/x86_64/kernel/process.c
+++ linux/arch/x86_64/kernel/process.c
@@ -527,8 +527,6 @@ __switch_to(struct task_struct *prev_p, 
 	int cpu = smp_processor_id();  
 	struct tss_struct *tss = &per_cpu(init_tss, cpu);
 
-	unlazy_fpu(prev_p);
-
 	/*
 	 * Reload esp0, LDT and the page table pointer:
 	 */
@@ -586,11 +584,14 @@ __switch_to(struct task_struct *prev_p, 
 	}
 
 	/* 
-	 * Switch the PDA context.
+	 * Switch the PDA and FPU contexts.
 	 */
 	prev->userrsp = read_pda(oldrsp); 
 	write_pda(oldrsp, next->userrsp); 
 	write_pda(pcurrent, next_p); 
+	/* This must be here to ensure both math_state_restore() and
+	   kernel_fpu_begin() work consistently. */
+	unlazy_fpu(prev_p);
 	write_pda(kernelstack,
 		  task_stack_page(next_p) + THREAD_SIZE - PDA_STACKOFFSET);
 
@@ -841,3 +842,13 @@ unsigned long arch_align_stack(unsigned 
 		sp -= get_random_int() % 8192;
 	return sp & ~0xf;
 }
+
+unsigned long last_clier;
+
+void local_irq_disable(void)
+{
+	if (!irqs_disabled()) {
+		last_clier = __builtin_return_address(0);
+		asm volatile("cli":::"memory"); 
+	}
+}
Index: linux/arch/x86_64/kernel/pmtimer.c
===================================================================
--- linux.orig/arch/x86_64/kernel/pmtimer.c
+++ linux/arch/x86_64/kernel/pmtimer.c
@@ -86,7 +86,7 @@ static unsigned pmtimer_wait_tick(void)
 	for (a = b = inl(pmtmr_ioport) & ACPI_PM_MASK;
 	     a == b;
 	     b = inl(pmtmr_ioport) & ACPI_PM_MASK)
-		;
+		cpu_relax();
 	return b;
 }
 
@@ -97,6 +97,7 @@ void pmtimer_wait(unsigned us)
 	a = pmtimer_wait_tick();
 	do {
 		b = inl(pmtmr_ioport);
+		cpu_relax();
 	} while (cyc2us(b - a) < us);
 }
 
-
: send the line "unsubscribe linux-x86_64" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html

[Index of Archives]     [Linux ia64]     [Linux Kernel]     [DCCP]     [Linux ARM]     [Yosemite News]     [Linux SCSI]     [Linux Hams]
  Powered by Linux