]> git.ipfire.org Git - people/arne_f/kernel.git/blob - arch/x86/realmode/rm/wakeup/wakeup_asm.S
8064e1c3591bc7b0849e42819b4c73cf440a0e0d
[people/arne_f/kernel.git] / arch / x86 / realmode / rm / wakeup / wakeup_asm.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 "../realmode.h"
10 #include "wakeup.h"
11
12 .code16
13
14 /* This should match the structure in wakeup.h */
15 .section ".data", "aw"
16 .globl wakeup_header
17 wakeup_header:
18 video_mode: .short 0 /* Video mode number */
19 pmode_entry: .long 0
20 pmode_cs: .short __KERNEL_CS
21 pmode_cr0: .long 0 /* Saved %cr0 */
22 pmode_cr3: .long 0 /* Saved %cr3 */
23 pmode_cr4: .long 0 /* Saved %cr4 */
24 pmode_efer: .quad 0 /* Saved EFER */
25 pmode_gdt: .quad 0
26 pmode_misc_en: .quad 0 /* Saved MISC_ENABLE MSR */
27 pmode_behavior: .long 0 /* Wakeup behavior flags */
28 realmode_flags: .long 0
29 real_magic: .long 0
30 signature: .long WAKEUP_HEADER_SIGNATURE
31 .size wakeup_header, .-wakeup_header
32
33 .text
34 .code16
35 .globl wakeup_start
36 wakeup_start:
37 cli
38 cld
39
40 LJMPW_RM(3f)
41 3:
42 /* Apparently some dimwit BIOS programmers don't know how to
43 program a PM to RM transition, and we might end up here with
44 junk in the data segment descriptor registers. The only way
45 to repair that is to go into PM and fix it ourselves... */
46 movw $16, %cx
47 lgdtl %cs:wakeup_gdt
48 movl %cr0, %eax
49 orb $X86_CR0_PE, %al
50 movl %eax, %cr0
51 ljmpw $8, $2f
52 2:
53 movw %cx, %ds
54 movw %cx, %es
55 movw %cx, %ss
56 movw %cx, %fs
57 movw %cx, %gs
58
59 andb $~X86_CR0_PE, %al
60 movl %eax, %cr0
61 LJMPW_RM(3f)
62 3:
63 /* Set up segments */
64 movw %cs, %ax
65 movw %ax, %ds
66 movw %ax, %es
67 movw %ax, %ss
68 lidtl wakeup_idt
69
70 movl $wakeup_stack_end, %esp
71
72 /* Clear the EFLAGS */
73 pushl $0
74 popfl
75
76 /* Check header signature... */
77 movl signature, %eax
78 cmpl $WAKEUP_HEADER_SIGNATURE, %eax
79 jne bogus_real_magic
80
81 /* Check we really have everything... */
82 movl end_signature, %eax
83 cmpl $WAKEUP_END_SIGNATURE, %eax
84 jne bogus_real_magic
85
86 /* Call the C code */
87 calll main
88
89 /* Restore MISC_ENABLE before entering protected mode, in case
90 BIOS decided to clear XD_DISABLE during S3. */
91 movl pmode_behavior, %eax
92 btl $WAKEUP_BEHAVIOR_RESTORE_MISC_ENABLE, %eax
93 jnc 1f
94
95 movl pmode_misc_en, %eax
96 movl pmode_misc_en + 4, %edx
97 movl $MSR_IA32_MISC_ENABLE, %ecx
98 wrmsr
99 1:
100
101 /* Do any other stuff... */
102
103 #ifndef CONFIG_64BIT
104 /* This could also be done in C code... */
105 movl pmode_cr3, %eax
106 movl %eax, %cr3
107
108 movl pmode_cr4, %ecx
109 jecxz 1f
110 movl %ecx, %cr4
111 1:
112 movl pmode_efer, %eax
113 movl pmode_efer + 4, %edx
114 movl %eax, %ecx
115 orl %edx, %ecx
116 jz 1f
117 movl $MSR_EFER, %ecx
118 wrmsr
119 1:
120
121 lgdtl pmode_gdt
122
123 /* This really couldn't... */
124 movl pmode_entry, %eax
125 movl pmode_cr0, %ecx
126 movl %ecx, %cr0
127 ljmpl $__KERNEL_CS, $pa_startup_32
128 /* -> jmp *%eax in trampoline_32.S */
129 #else
130 jmp trampoline_data
131 #endif
132
133 bogus_real_magic:
134 1:
135 hlt
136 jmp 1b
137
138 .section ".rodata","a"
139
140 /*
141 * Set up the wakeup GDT. We set these up as Big Real Mode,
142 * that is, with limits set to 4 GB. At least the Lenovo
143 * Thinkpad X61 is known to need this for the video BIOS
144 * initialization quirk to work; this is likely to also
145 * be the case for other laptops or integrated video devices.
146 */
147
148 .globl wakeup_gdt
149 .balign 16
150 wakeup_gdt:
151 .word 3*8-1 /* Self-descriptor */
152 .long pa_wakeup_gdt
153 .word 0
154
155 .word 0xffff /* 16-bit code segment @ real_mode_base */
156 .long 0x9b000000 + pa_real_mode_base
157 .word 0x008f /* big real mode */
158
159 .word 0xffff /* 16-bit data segment @ real_mode_base */
160 .long 0x93000000 + pa_real_mode_base
161 .word 0x008f /* big real mode */
162 .size wakeup_gdt, .-wakeup_gdt
163
164 .data
165 .balign 8
166
167 /* This is the standard real-mode IDT */
168 wakeup_idt:
169 .word 0xffff /* limit */
170 .long 0 /* address */
171 .word 0
172
173 .globl HEAP, heap_end
174 HEAP:
175 .long wakeup_heap
176 heap_end:
177 .long wakeup_stack
178
179 .bss
180 wakeup_heap:
181 .space 2048
182 wakeup_stack:
183 .space 2048
184 wakeup_stack_end:
185
186 .section ".signature","a"
187 end_signature:
188 .long WAKEUP_END_SIGNATURE