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