Source-Changes-HG archive

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

[src/trunk]: src/sys/arch/x86/acpi There is a huge fpu synchronization issue ...



details:   https://anonhg.NetBSD.org/src/rev/6e0b6e9c61d1
branches:  trunk
changeset: 348490:6e0b6e9c61d1
user:      maxv <maxv%NetBSD.org@localhost>
date:      Thu Oct 20 16:05:04 2016 +0000

description:
There is a huge fpu synchronization issue here.

When the remote CPUs receive the ACPI sleep IPI, they do not save the fpu
state of the lwp they are executing. The problem is, when waking up they
reinitialize the registers of their local fpu and go back to their lwp
directly. Therefore, if an lwp is interrupted while storing data in an fpu
register, that data gets overwritten, which basically means the lwp is
likely to go crazy when resuming execution.

Fix this by simply saving the fpu state correctly. This way when going to
sleep the state is stored in the lwp's pcb and CR0_TS is set, so the next
time the lwp wants to use the fpu we'll get a dna, and the state will be
restored as expected.

While here, don't forget to reenable interrupts (and the spl) if an error
occurs.

diffstat:

 sys/arch/x86/acpi/acpi_wakeup.c |  12 +++++++++---
 1 files changed, 9 insertions(+), 3 deletions(-)

diffs (47 lines):

diff -r f4901abe85a6 -r 6e0b6e9c61d1 sys/arch/x86/acpi/acpi_wakeup.c
--- a/sys/arch/x86/acpi/acpi_wakeup.c   Thu Oct 20 14:06:18 2016 +0000
+++ b/sys/arch/x86/acpi/acpi_wakeup.c   Thu Oct 20 16:05:04 2016 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: acpi_wakeup.c,v 1.44 2016/10/20 14:06:18 maxv Exp $    */
+/*     $NetBSD: acpi_wakeup.c,v 1.45 2016/10/20 16:05:04 maxv Exp $    */
 
 /*-
  * Copyright (c) 2002, 2011 The NetBSD Foundation, Inc.
@@ -59,7 +59,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: acpi_wakeup.c,v 1.44 2016/10/20 14:06:18 maxv Exp $");
+__KERNEL_RCSID(0, "$NetBSD: acpi_wakeup.c,v 1.45 2016/10/20 16:05:04 maxv Exp $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -250,13 +250,17 @@
 void
 acpi_cpu_sleep(struct cpu_info *ci)
 {
+       int s;
+
        KASSERT(!CPU_IS_PRIMARY(ci));
        KASSERT(ci == curcpu());
 
+       s = splhigh();
+       fpusave_cpu(true);
        x86_disable_intr();
 
        if (acpi_md_sleep_prepare(-1))
-               return;
+               goto out;
 
        /* Execute Wakeup */
        cpu_init_msrs(ci, false);
@@ -272,7 +276,9 @@
        kcpuset_atomic_set(kcpuset_running, cpu_index(ci));
        tsc_sync_ap(ci);
 
+out:
        x86_enable_intr();
+       splx(s);
 }
 #endif
 



Home | Main Index | Thread Index | Old Index