Module Name: src
Committed By: maxv
Date: Sun Jul 24 14:09:22 UTC 2016
Modified Files:
src/sys/arch/i386/acpi: acpi_wakecode.S acpi_wakeup_low.S
src/sys/arch/x86/acpi: acpi_wakeup.c
Log Message:
The MSR EFER state is not saved and restored when sleeping on i386. On PAE,
the CPU crashes right after waking up, since it needs to access NOX-ed
pages, which are to be enabled in an MSR.
Fix this by properly saving and restoring the EFER MSR. It's a little
tricky since the wakeup code uses %edx, but rdmsr overwrites it. We just
save it in %esi.
Now, the CPU sleeps properly on PAE kernels.
To generate a diff of this commit:
cvs rdiff -u -r1.17 -r1.18 src/sys/arch/i386/acpi/acpi_wakecode.S
cvs rdiff -u -r1.6 -r1.7 src/sys/arch/i386/acpi/acpi_wakeup_low.S
cvs rdiff -u -r1.39 -r1.40 src/sys/arch/x86/acpi/acpi_wakeup.c
Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.
Modified files:
Index: src/sys/arch/i386/acpi/acpi_wakecode.S
diff -u src/sys/arch/i386/acpi/acpi_wakecode.S:1.17 src/sys/arch/i386/acpi/acpi_wakecode.S:1.18
--- src/sys/arch/i386/acpi/acpi_wakecode.S:1.17 Sun Jul 24 13:04:58 2016
+++ src/sys/arch/i386/acpi/acpi_wakecode.S Sun Jul 24 14:09:22 2016
@@ -1,4 +1,4 @@
-/* $NetBSD: acpi_wakecode.S,v 1.17 2016/07/24 13:04:58 maxv Exp $ */
+/* $NetBSD: acpi_wakecode.S,v 1.18 2016/07/24 14:09:22 maxv Exp $ */
/*-
* Copyright (c) 2002 The NetBSD Foundation, Inc.
@@ -159,6 +159,13 @@ wakeup_32:
movl WAKEUP_r_cr4 + ACPI_WAKEUP_ADDR,%eax
movl %eax,%cr4
+ /*
+ * Load the correct MSR EFER value now to not depend on the
+ * data segment register. After this point, no instruction is
+ * allowed to clobber %ebx until wrmsr.
+ */
+ movl WAKEUP_efer + ACPI_WAKEUP_ADDR,%ebx
+
/* Load temporary page table, we will switch to full page table later */
movl WAKEUP_r_cr3 + ACPI_WAKEUP_ADDR,%eax
movl %eax,%cr3
@@ -175,6 +182,15 @@ wakeup_32:
nop
+ /*
+ * Load the normal system value of MSR EFER. This includes
+ * enabling NXE (if supported).
+ */
+ movl %ebx,%eax
+ movl $0,%edx
+ movl $MSR_EFER,%ecx
+ wrmsr
+
/* Restore registers */
movl WAKEUP_curcpu + ACPI_WAKEUP_ADDR,%edx
movl WAKEUP_restorecpu + ACPI_WAKEUP_ADDR,%ebx
@@ -209,6 +225,8 @@ WAKEUP_r_cr4: .long 0
WAKEUP_curcpu: .long 0
.global WAKEUP_restorecpu
WAKEUP_restorecpu: .long 0
+ .global WAKEUP_efer
+WAKEUP_efer: .long 0
.global WAKEUP_vbios_reset
WAKEUP_vbios_reset: .byte 0
Index: src/sys/arch/i386/acpi/acpi_wakeup_low.S
diff -u src/sys/arch/i386/acpi/acpi_wakeup_low.S:1.6 src/sys/arch/i386/acpi/acpi_wakeup_low.S:1.7
--- src/sys/arch/i386/acpi/acpi_wakeup_low.S:1.6 Sun Jul 24 13:04:58 2016
+++ src/sys/arch/i386/acpi/acpi_wakeup_low.S Sun Jul 24 14:09:22 2016
@@ -1,4 +1,4 @@
-/* $NetBSD: acpi_wakeup_low.S,v 1.6 2016/07/24 13:04:58 maxv Exp $ */
+/* $NetBSD: acpi_wakeup_low.S,v 1.7 2016/07/24 14:09:22 maxv Exp $ */
/*-
* Copyright (c) 2007 Joerg Sonnenberger <[email protected]>
@@ -29,10 +29,11 @@
*/
#include <machine/asm.h>
-__KERNEL_RCSID(0, "$NetBSD: acpi_wakeup_low.S,v 1.6 2016/07/24 13:04:58 maxv Exp $");
+__KERNEL_RCSID(0, "$NetBSD: acpi_wakeup_low.S,v 1.7 2016/07/24 14:09:22 maxv Exp $");
#include "assym.h"
#include <machine/segments.h>
+#include <machine/specialreg.h>
.text
.p2align 2, 0x90
@@ -51,6 +52,13 @@ acpi_md_sleep_exit:
movw ACPI_SUSPEND_GS(%edx),%ax
movw %ax,%gs
+ movl $MSR_EFER,%ecx
+ movl ACPI_SUSPEND_EFER(%edx),%eax
+ movl %edx,%esi
+ movl $0,%edx
+ wrmsr
+ movl %esi,%edx
+
movl ACPI_SUSPEND_CR2(%edx),%eax
movl %eax,%cr2
movl ACPI_SUSPEND_CR4(%edx),%eax
@@ -96,6 +104,11 @@ acpi_md_sleep_prepare:
movl %ebp,ACPI_SUSPEND_REG+(3*4)(%edx)
movl %esp,ACPI_SUSPEND_REG+(4*4)(%edx)
+ movl $MSR_EFER,%ecx
+ rdmsr
+ movl CPUVAR(SELF),%edx
+ movl %eax,ACPI_SUSPEND_EFER(%edx)
+
movl %cr0,%eax
movl %eax,ACPI_SUSPEND_CR0(%edx)
movl %cr2,%eax
Index: src/sys/arch/x86/acpi/acpi_wakeup.c
diff -u src/sys/arch/x86/acpi/acpi_wakeup.c:1.39 src/sys/arch/x86/acpi/acpi_wakeup.c:1.40
--- src/sys/arch/x86/acpi/acpi_wakeup.c:1.39 Tue Aug 18 10:42:41 2015
+++ src/sys/arch/x86/acpi/acpi_wakeup.c Sun Jul 24 14:09:22 2016
@@ -1,4 +1,4 @@
-/* $NetBSD: acpi_wakeup.c,v 1.39 2015/08/18 10:42:41 christos Exp $ */
+/* $NetBSD: acpi_wakeup.c,v 1.40 2016/07/24 14:09:22 maxv Exp $ */
/*-
* Copyright (c) 2002, 2011 The NetBSD Foundation, Inc.
@@ -30,7 +30,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: acpi_wakeup.c,v 1.39 2015/08/18 10:42:41 christos Exp $");
+__KERNEL_RCSID(0, "$NetBSD: acpi_wakeup.c,v 1.40 2016/07/24 14:09:22 maxv Exp $");
/*-
* Copyright (c) 2001 Takanori Watanabe <[email protected]>
@@ -62,7 +62,7 @@ __KERNEL_RCSID(0, "$NetBSD: acpi_wakeup.
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: acpi_wakeup.c,v 1.39 2015/08/18 10:42:41 christos Exp $");
+__KERNEL_RCSID(0, "$NetBSD: acpi_wakeup.c,v 1.40 2016/07/24 14:09:22 maxv Exp $");
#include <sys/param.h>
#include <sys/systm.h>
@@ -165,10 +165,8 @@ acpi_md_sleep_patch(struct cpu_info *ci)
#ifdef __i386__
WAKECODE_FIXUP(WAKEUP_r_cr4, uint32_t, ci->ci_suspend_cr4);
-#else
- WAKECODE_FIXUP(WAKEUP_efer, uint32_t, ci->ci_suspend_efer);
#endif
-
+ WAKECODE_FIXUP(WAKEUP_efer, uint32_t, ci->ci_suspend_efer);
WAKECODE_FIXUP(WAKEUP_curcpu, void *, ci);
#ifdef __i386__
WAKECODE_FIXUP(WAKEUP_r_cr3, uint32_t, tmp_pdir);