x86, suspend: Restore MISC_ENABLE MSR in realmode wakeup
[linux-2.6.git] / arch / x86 / kernel / acpi / realmode / wakeup.S
1 /*
2  * ACPI wakeup real mode startup stub
3  */
4 #include <asm/segment.h>
5 #include <asm/msr-index.h>
6 #include <asm/page_types.h>
7 #include <asm/pgtable_types.h>
8 #include <asm/processor-flags.h>
9 #include "wakeup.h"
10
11         .code16
12         .section ".jump", "ax"
13         .globl  _start
14 _start:
15         cli
16         jmp     wakeup_code
17
18 /* This should match the structure in wakeup.h */
19                 .section ".header", "a"
20                 .globl  wakeup_header
21 wakeup_header:
22 video_mode:     .short  0       /* Video mode number */
23 pmode_return:   .byte   0x66, 0xea      /* ljmpl */
24                 .long   0       /* offset goes here */
25                 .short  __KERNEL_CS
26 pmode_cr0:      .long   0       /* Saved %cr0 */
27 pmode_cr3:      .long   0       /* Saved %cr3 */
28 pmode_cr4:      .long   0       /* Saved %cr4 */
29 pmode_efer:     .quad   0       /* Saved EFER */
30 pmode_gdt:      .quad   0
31 pmode_misc_en:  .quad   0       /* Saved MISC_ENABLE MSR */
32 pmode_behavior: .long   0       /* Wakeup behavior flags */
33 realmode_flags: .long   0
34 real_magic:     .long   0
35 trampoline_segment:     .word 0
36 _pad1:          .byte   0
37 wakeup_jmp:     .byte   0xea    /* ljmpw */
38 wakeup_jmp_off: .word   3f
39 wakeup_jmp_seg: .word   0
40 wakeup_gdt:     .quad   0, 0, 0
41 signature:      .long   WAKEUP_HEADER_SIGNATURE
42
43         .text
44         .code16
45 wakeup_code:
46         cld
47
48         /* Apparently some dimwit BIOS programmers don't know how to
49            program a PM to RM transition, and we might end up here with
50            junk in the data segment descriptor registers.  The only way
51            to repair that is to go into PM and fix it ourselves... */
52         movw    $16, %cx
53         lgdtl   %cs:wakeup_gdt
54         movl    %cr0, %eax
55         orb     $X86_CR0_PE, %al
56         movl    %eax, %cr0
57         jmp     1f
58 1:      ljmpw   $8, $2f
59 2:
60         movw    %cx, %ds
61         movw    %cx, %es
62         movw    %cx, %ss
63         movw    %cx, %fs
64         movw    %cx, %gs
65
66         andb    $~X86_CR0_PE, %al
67         movl    %eax, %cr0
68         jmp     wakeup_jmp
69 3:
70         /* Set up segments */
71         movw    %cs, %ax
72         movw    %ax, %ds
73         movw    %ax, %es
74         movw    %ax, %ss
75         lidtl   wakeup_idt
76
77         movl    $wakeup_stack_end, %esp
78
79         /* Clear the EFLAGS */
80         pushl   $0
81         popfl
82
83         /* Check header signature... */
84         movl    signature, %eax
85         cmpl    $WAKEUP_HEADER_SIGNATURE, %eax
86         jne     bogus_real_magic
87
88         /* Check we really have everything... */
89         movl    end_signature, %eax
90         cmpl    $WAKEUP_END_SIGNATURE, %eax
91         jne     bogus_real_magic
92
93         /* Call the C code */
94         calll   main
95
96         /* Restore MISC_ENABLE before entering protected mode, in case
97            BIOS decided to clear XD_DISABLE during S3. */
98         movl    pmode_behavior, %eax
99         btl     $WAKEUP_BEHAVIOR_RESTORE_MISC_ENABLE, %eax
100         jnc     1f
101
102         movl    pmode_misc_en, %eax
103         movl    pmode_misc_en + 4, %edx
104         movl    $MSR_IA32_MISC_ENABLE, %ecx
105         wrmsr
106 1:
107
108         /* Do any other stuff... */
109
110 #ifndef CONFIG_64BIT
111         /* This could also be done in C code... */
112         movl    pmode_cr3, %eax
113         movl    %eax, %cr3
114
115         movl    pmode_cr4, %ecx
116         jecxz   1f
117         movl    %ecx, %cr4
118 1:
119         movl    pmode_efer, %eax
120         movl    pmode_efer + 4, %edx
121         movl    %eax, %ecx
122         orl     %edx, %ecx
123         jz      1f
124         movl    $MSR_EFER, %ecx
125         wrmsr
126 1:
127
128         lgdtl   pmode_gdt
129
130         /* This really couldn't... */
131         movl    pmode_cr0, %eax
132         movl    %eax, %cr0
133         jmp     pmode_return
134 #else
135         pushw   $0
136         pushw   trampoline_segment
137         pushw   $0
138         lret
139 #endif
140
141 bogus_real_magic:
142 1:
143         hlt
144         jmp     1b
145
146         .data
147         .balign 8
148
149         /* This is the standard real-mode IDT */
150 wakeup_idt:
151         .word   0xffff          /* limit */
152         .long   0               /* address */
153         .word   0
154
155         .globl  HEAP, heap_end
156 HEAP:
157         .long   wakeup_heap
158 heap_end:
159         .long   wakeup_stack
160
161         .bss
162 wakeup_heap:
163         .space  2048
164 wakeup_stack:
165         .space  2048
166 wakeup_stack_end:
167
168         .section ".signature","a"
169 end_signature:
170         .long   WAKEUP_END_SIGNATURE