Linux 4.1.18
[linux/fpc-iii.git] / arch / x86 / realmode / rm / wakeup_asm.S
blob9e7e14797a72dda0b85d4c70afca61fdb2fdf92e
1 /*
2  * ACPI wakeup real mode startup stub
3  */
4 #include <linux/linkage.h>
5 #include <asm/segment.h>
6 #include <asm/msr-index.h>
7 #include <asm/page_types.h>
8 #include <asm/pgtable_types.h>
9 #include <asm/processor-flags.h>
10 #include "realmode.h"
11 #include "wakeup.h"
13         .code16
15 /* This should match the structure in wakeup.h */
16         .section ".data", "aw"
18         .balign 16
19 GLOBAL(wakeup_header)
20         video_mode:     .short  0       /* Video mode number */
21         pmode_entry:    .long   0
22         pmode_cs:       .short  __KERNEL_CS
23         pmode_cr0:      .long   0       /* Saved %cr0 */
24         pmode_cr3:      .long   0       /* Saved %cr3 */
25         pmode_cr4:      .long   0       /* Saved %cr4 */
26         pmode_efer:     .quad   0       /* Saved EFER */
27         pmode_gdt:      .quad   0
28         pmode_misc_en:  .quad   0       /* Saved MISC_ENABLE MSR */
29         pmode_behavior: .long   0       /* Wakeup behavior flags */
30         realmode_flags: .long   0
31         real_magic:     .long   0
32         signature:      .long   WAKEUP_HEADER_SIGNATURE
33 END(wakeup_header)
35         .text
36         .code16
38         .balign 16
39 ENTRY(wakeup_start)
40         cli
41         cld
43         LJMPW_RM(3f)
45         /* Apparently some dimwit BIOS programmers don't know how to
46            program a PM to RM transition, and we might end up here with
47            junk in the data segment descriptor registers.  The only way
48            to repair that is to go into PM and fix it ourselves... */
49         movw    $16, %cx
50         lgdtl   %cs:wakeup_gdt
51         movl    %cr0, %eax
52         orb     $X86_CR0_PE, %al
53         movl    %eax, %cr0
54         ljmpw   $8, $2f
56         movw    %cx, %ds
57         movw    %cx, %es
58         movw    %cx, %ss
59         movw    %cx, %fs
60         movw    %cx, %gs
62         andb    $~X86_CR0_PE, %al
63         movl    %eax, %cr0
64         LJMPW_RM(3f)
66         /* Set up segments */
67         movw    %cs, %ax
68         movw    %ax, %ss
69         movl    $rm_stack_end, %esp
70         movw    %ax, %ds
71         movw    %ax, %es
72         movw    %ax, %fs
73         movw    %ax, %gs
75         lidtl   wakeup_idt
77         /* Clear the EFLAGS */
78         pushl $0
79         popfl
81         /* Check header signature... */
82         movl    signature, %eax
83         cmpl    $WAKEUP_HEADER_SIGNATURE, %eax
84         jne     bogus_real_magic
86         /* Check we really have everything... */
87         movl    end_signature, %eax
88         cmpl    $REALMODE_END_SIGNATURE, %eax
89         jne     bogus_real_magic
91         /* Call the C code */
92         calll   main
94         /* Restore MISC_ENABLE before entering protected mode, in case
95            BIOS decided to clear XD_DISABLE during S3. */
96         movl    pmode_behavior, %edi
97         btl     $WAKEUP_BEHAVIOR_RESTORE_MISC_ENABLE, %edi
98         jnc     1f
100         movl    pmode_misc_en, %eax
101         movl    pmode_misc_en + 4, %edx
102         movl    $MSR_IA32_MISC_ENABLE, %ecx
103         wrmsr
106         /* Do any other stuff... */
108 #ifndef CONFIG_64BIT
109         /* This could also be done in C code... */
110         movl    pmode_cr3, %eax
111         movl    %eax, %cr3
113         btl     $WAKEUP_BEHAVIOR_RESTORE_CR4, %edi
114         jnc     1f
115         movl    pmode_cr4, %eax
116         movl    %eax, %cr4
118         btl     $WAKEUP_BEHAVIOR_RESTORE_EFER, %edi
119         jnc     1f
120         movl    pmode_efer, %eax
121         movl    pmode_efer + 4, %edx
122         movl    $MSR_EFER, %ecx
123         wrmsr
126         lgdtl   pmode_gdt
128         /* This really couldn't... */
129         movl    pmode_entry, %eax
130         movl    pmode_cr0, %ecx
131         movl    %ecx, %cr0
132         ljmpl   $__KERNEL_CS, $pa_startup_32
133         /* -> jmp *%eax in trampoline_32.S */
134 #else
135         jmp     trampoline_start
136 #endif
138 bogus_real_magic:
140         hlt
141         jmp     1b
143         .section ".rodata","a"
145         /*
146          * Set up the wakeup GDT.  We set these up as Big Real Mode,
147          * that is, with limits set to 4 GB.  At least the Lenovo
148          * Thinkpad X61 is known to need this for the video BIOS
149          * initialization quirk to work; this is likely to also
150          * be the case for other laptops or integrated video devices.
151          */
153         .balign 16
154 GLOBAL(wakeup_gdt)
155         .word   3*8-1           /* Self-descriptor */
156         .long   pa_wakeup_gdt
157         .word   0
159         .word   0xffff          /* 16-bit code segment @ real_mode_base */
160         .long   0x9b000000 + pa_real_mode_base
161         .word   0x008f          /* big real mode */
163         .word   0xffff          /* 16-bit data segment @ real_mode_base */
164         .long   0x93000000 + pa_real_mode_base
165         .word   0x008f          /* big real mode */
166 END(wakeup_gdt)
168         .section ".rodata","a"
169         .balign 8
171         /* This is the standard real-mode IDT */
172         .balign 16
173 GLOBAL(wakeup_idt)
174         .word   0xffff          /* limit */
175         .long   0               /* address */
176         .word   0
177 END(wakeup_idt)