x86, suspend: On wakeup always initialize cr4 and EFER
authorH. Peter Anvin <hpa@linux.intel.com>
Wed, 26 Sep 2012 22:02:34 +0000 (15:02 -0700)
committerH. Peter Anvin <hpa@linux.intel.com>
Wed, 26 Sep 2012 22:06:22 +0000 (15:06 -0700)
We already have a flag word to indicate the existence of MISC_ENABLES,
so use the same flag word to indicate existence of cr4 and EFER, and
always restore them if they exist.  That way if something passes a
nonzero value when the value *should* be zero, we will still
initialize it.

Signed-off-by: H. Peter Anvin <hpa@linux.intel.com>
Cc: Rafael J. Wysocki <rjw@sisk.pl>
Link: http://lkml.kernel.org/r/1348529239-17943-1-git-send-email-hpa@linux.intel.com
arch/x86/kernel/acpi/sleep.c
arch/x86/realmode/rm/wakeup.h
arch/x86/realmode/rm/wakeup_asm.S

index 1b8e5a03d942439c4b58a7470f181dcb99b29e85..11676cf65aee5ee51b64c8fadda0261c1f38599f 100644 (file)
@@ -43,17 +43,22 @@ int acpi_suspend_lowlevel(void)
 
        header->video_mode = saved_video_mode;
 
+       header->pmode_behavior = 0;
+
 #ifndef CONFIG_64BIT
        store_gdt((struct desc_ptr *)&header->pmode_gdt);
 
-       if (rdmsr_safe(MSR_EFER, &header->pmode_efer_low,
-                      &header->pmode_efer_high))
-               header->pmode_efer_low = header->pmode_efer_high = 0;
+       if (!rdmsr_safe(MSR_EFER,
+                       &header->pmode_efer_low,
+                       &header->pmode_efer_high))
+               header->pmode_behavior |= (1 << WAKEUP_BEHAVIOR_RESTORE_EFER);
 #endif /* !CONFIG_64BIT */
 
        header->pmode_cr0 = read_cr0();
-       header->pmode_cr4 = read_cr4_safe();
-       header->pmode_behavior = 0;
+       if (__this_cpu_read(cpu_info.cpuid_level) >= 0) {
+               header->pmode_cr4 = read_cr4();
+               header->pmode_behavior |= (1 << WAKEUP_BEHAVIOR_RESTORE_CR4);
+       }
        if (!rdmsr_safe(MSR_IA32_MISC_ENABLE,
                        &header->pmode_misc_en_low,
                        &header->pmode_misc_en_high))
index 9317e0042f24b9f49d3e5d5eafac20424bea574d..7dd86a419f5d215401ef66627eb388b2cddd5f14 100644 (file)
@@ -36,5 +36,7 @@ extern struct wakeup_header wakeup_header;
 
 /* Wakeup behavior bits */
 #define WAKEUP_BEHAVIOR_RESTORE_MISC_ENABLE     0
+#define WAKEUP_BEHAVIOR_RESTORE_CR4            1
+#define WAKEUP_BEHAVIOR_RESTORE_EFER           2
 
 #endif /* ARCH_X86_KERNEL_ACPI_RM_WAKEUP_H */
index 8905166b0bbb2021fe9a6eecbda5c185f70847bd..e56479e580534ffd0cd5b3eb70531d4dd716869f 100644 (file)
@@ -74,9 +74,18 @@ ENTRY(wakeup_start)
 
        lidtl   wakeup_idt
 
-       /* Clear the EFLAGS */
-       pushl   $0
+       /* Clear the EFLAGS but remember if we have EFLAGS.ID */
+       movl $X86_EFLAGS_ID, %ecx
+       pushl %ecx
        popfl
+       pushfl
+       popl %edi
+       pushl $0
+       popfl
+       pushfl
+       popl %edx
+       xorl %edx, %edi
+       andl %ecx, %edi         /* %edi is zero iff CPUID & %cr4 are missing */
 
        /* Check header signature... */
        movl    signature, %eax
@@ -93,8 +102,8 @@ ENTRY(wakeup_start)
 
        /* Restore MISC_ENABLE before entering protected mode, in case
           BIOS decided to clear XD_DISABLE during S3. */
-       movl    pmode_behavior, %eax
-       btl     $WAKEUP_BEHAVIOR_RESTORE_MISC_ENABLE, %eax
+       movl    pmode_behavior, %edi
+       btl     $WAKEUP_BEHAVIOR_RESTORE_MISC_ENABLE, %edi
        jnc     1f
 
        movl    pmode_misc_en, %eax
@@ -110,15 +119,15 @@ ENTRY(wakeup_start)
        movl    pmode_cr3, %eax
        movl    %eax, %cr3
 
-       movl    pmode_cr4, %ecx
-       jecxz   1f
-       movl    %ecx, %cr4
+       btl     $WAKEUP_BEHAVIOR_RESTORE_CR4, %edi
+       jz      1f
+       movl    pmode_cr4, %eax
+       movl    %eax, %cr4
 1:
+       btl     $WAKEUP_BEHAVIOR_RESTORE_EFER, %edi
+       jz      1f
        movl    pmode_efer, %eax
        movl    pmode_efer + 4, %edx
-       movl    %eax, %ecx
-       orl     %edx, %ecx
-       jz      1f
        movl    $MSR_EFER, %ecx
        wrmsr
 1: