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);