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 <jo...@netbsd.org>
@@ -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 <takaw...@jp.freebsd.org>
@@ -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);

Reply via email to