diff options
author | Jarkko Sakkinen <jarkko.sakkinen@intel.com> | 2012-05-08 14:22:42 -0400 |
---|---|---|
committer | H. Peter Anvin <hpa@linux.intel.com> | 2012-05-08 14:48:45 -0400 |
commit | c4845474a01f699966272536e8416222e3f2d2cb (patch) | |
tree | 8d590924f5ab164981368822f7534f42eaabae30 /arch/x86/realmode/rm/wakeup_asm.S | |
parent | b429dbf6e866bd6dadb56fae66f61f611cde57ff (diff) |
x86, realmode: flattened rm hierachy
Simplified hierarchy under rm directory to a flat
directory because it is not anymore really justified
to have own directory for wakeup code. It only adds
more complexity.
Signed-off-by: Jarkko Sakkinen <jarkko.sakkinen@intel.com>
Link: http://lkml.kernel.org/r/1336501366-28617-20-git-send-email-jarkko.sakkinen@intel.com
Signed-off-by: H. Peter Anvin <hpa@linux.intel.com>
Diffstat (limited to 'arch/x86/realmode/rm/wakeup_asm.S')
-rw-r--r-- | arch/x86/realmode/rm/wakeup_asm.S | 181 |
1 files changed, 181 insertions, 0 deletions
diff --git a/arch/x86/realmode/rm/wakeup_asm.S b/arch/x86/realmode/rm/wakeup_asm.S new file mode 100644 index 000000000000..8a57c5a05fbc --- /dev/null +++ b/arch/x86/realmode/rm/wakeup_asm.S | |||
@@ -0,0 +1,181 @@ | |||
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" | ||
12 | |||
13 | .code16 | ||
14 | |||
15 | /* This should match the structure in wakeup.h */ | ||
16 | .section ".data", "aw" | ||
17 | |||
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) | ||
34 | |||
35 | .text | ||
36 | .code16 | ||
37 | |||
38 | .balign 16 | ||
39 | ENTRY(wakeup_start) | ||
40 | cli | ||
41 | cld | ||
42 | |||
43 | LJMPW_RM(3f) | ||
44 | 3: | ||
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 | ||
55 | 2: | ||
56 | movw %cx, %ds | ||
57 | movw %cx, %es | ||
58 | movw %cx, %ss | ||
59 | movw %cx, %fs | ||
60 | movw %cx, %gs | ||
61 | |||
62 | andb $~X86_CR0_PE, %al | ||
63 | movl %eax, %cr0 | ||
64 | LJMPW_RM(3f) | ||
65 | 3: | ||
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 | ||
74 | |||
75 | lidtl wakeup_idt | ||
76 | |||
77 | /* Clear the EFLAGS */ | ||
78 | pushl $0 | ||
79 | popfl | ||
80 | |||
81 | /* Check header signature... */ | ||
82 | movl signature, %eax | ||
83 | cmpl $WAKEUP_HEADER_SIGNATURE, %eax | ||
84 | jne bogus_real_magic | ||
85 | |||
86 | /* Check we really have everything... */ | ||
87 | movl end_signature, %eax | ||
88 | cmpl $WAKEUP_END_SIGNATURE, %eax | ||
89 | jne bogus_real_magic | ||
90 | |||
91 | /* Call the C code */ | ||
92 | calll main | ||
93 | |||
94 | /* Restore MISC_ENABLE before entering protected mode, in case | ||
95 | BIOS decided to clear XD_DISABLE during S3. */ | ||
96 | movl pmode_behavior, %eax | ||
97 | btl $WAKEUP_BEHAVIOR_RESTORE_MISC_ENABLE, %eax | ||
98 | jnc 1f | ||
99 | |||
100 | movl pmode_misc_en, %eax | ||
101 | movl pmode_misc_en + 4, %edx | ||
102 | movl $MSR_IA32_MISC_ENABLE, %ecx | ||
103 | wrmsr | ||
104 | 1: | ||
105 | |||
106 | /* Do any other stuff... */ | ||
107 | |||
108 | #ifndef CONFIG_64BIT | ||
109 | /* This could also be done in C code... */ | ||
110 | movl pmode_cr3, %eax | ||
111 | movl %eax, %cr3 | ||
112 | |||
113 | movl pmode_cr4, %ecx | ||
114 | jecxz 1f | ||
115 | movl %ecx, %cr4 | ||
116 | 1: | ||
117 | movl pmode_efer, %eax | ||
118 | movl pmode_efer + 4, %edx | ||
119 | movl %eax, %ecx | ||
120 | orl %edx, %ecx | ||
121 | jz 1f | ||
122 | movl $MSR_EFER, %ecx | ||
123 | wrmsr | ||
124 | 1: | ||
125 | |||
126 | lgdtl pmode_gdt | ||
127 | |||
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_data | ||
136 | #endif | ||
137 | |||
138 | bogus_real_magic: | ||
139 | 1: | ||
140 | hlt | ||
141 | jmp 1b | ||
142 | |||
143 | .section ".rodata","a" | ||
144 | |||
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 | */ | ||
152 | |||
153 | .balign 16 | ||
154 | GLOBAL(wakeup_gdt) | ||
155 | .word 3*8-1 /* Self-descriptor */ | ||
156 | .long pa_wakeup_gdt | ||
157 | .word 0 | ||
158 | |||
159 | .word 0xffff /* 16-bit code segment @ real_mode_base */ | ||
160 | .long 0x9b000000 + pa_real_mode_base | ||
161 | .word 0x008f /* big real mode */ | ||
162 | |||
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) | ||
167 | |||
168 | .section ".rodata","a" | ||
169 | .balign 8 | ||
170 | |||
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) | ||
178 | |||
179 | .section ".signature","a" | ||
180 | end_signature: | ||
181 | .long WAKEUP_END_SIGNATURE | ||