diff options
author | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
commit | 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch) | |
tree | 0bba044c4ce775e45a88a51686b5d9f90697ea9d /arch/i386/kernel/acpi/wakeup.S |
Linux-2.6.12-rc2v2.6.12-rc2
Initial git repository build. I'm not bothering with the full history,
even though we have it. We can create a separate "historical" git
archive of that later if we want to, and in the meantime it's about
3.2GB when imported into git - space that would just make the early
git days unnecessarily complicated, when we don't have a lot of good
infrastructure for it.
Let it rip!
Diffstat (limited to 'arch/i386/kernel/acpi/wakeup.S')
-rw-r--r-- | arch/i386/kernel/acpi/wakeup.S | 318 |
1 files changed, 318 insertions, 0 deletions
diff --git a/arch/i386/kernel/acpi/wakeup.S b/arch/i386/kernel/acpi/wakeup.S new file mode 100644 index 000000000000..39d32484f6f5 --- /dev/null +++ b/arch/i386/kernel/acpi/wakeup.S | |||
@@ -0,0 +1,318 @@ | |||
1 | .text | ||
2 | #include <linux/linkage.h> | ||
3 | #include <asm/segment.h> | ||
4 | #include <asm/page.h> | ||
5 | |||
6 | # | ||
7 | # wakeup_code runs in real mode, and at unknown address (determined at run-time). | ||
8 | # Therefore it must only use relative jumps/calls. | ||
9 | # | ||
10 | # Do we need to deal with A20? It is okay: ACPI specs says A20 must be enabled | ||
11 | # | ||
12 | # If physical address of wakeup_code is 0x12345, BIOS should call us with | ||
13 | # cs = 0x1234, eip = 0x05 | ||
14 | # | ||
15 | |||
16 | ALIGN | ||
17 | .align 4096 | ||
18 | ENTRY(wakeup_start) | ||
19 | wakeup_code: | ||
20 | wakeup_code_start = . | ||
21 | .code16 | ||
22 | |||
23 | movw $0xb800, %ax | ||
24 | movw %ax,%fs | ||
25 | movw $0x0e00 + 'L', %fs:(0x10) | ||
26 | |||
27 | cli | ||
28 | cld | ||
29 | |||
30 | # setup data segment | ||
31 | movw %cs, %ax | ||
32 | movw %ax, %ds # Make ds:0 point to wakeup_start | ||
33 | movw %ax, %ss | ||
34 | mov $(wakeup_stack - wakeup_code), %sp # Private stack is needed for ASUS board | ||
35 | movw $0x0e00 + 'S', %fs:(0x12) | ||
36 | |||
37 | pushl $0 # Kill any dangerous flags | ||
38 | popfl | ||
39 | |||
40 | movl real_magic - wakeup_code, %eax | ||
41 | cmpl $0x12345678, %eax | ||
42 | jne bogus_real_magic | ||
43 | |||
44 | testl $1, video_flags - wakeup_code | ||
45 | jz 1f | ||
46 | lcall $0xc000,$3 | ||
47 | movw %cs, %ax | ||
48 | movw %ax, %ds # Bios might have played with that | ||
49 | movw %ax, %ss | ||
50 | 1: | ||
51 | |||
52 | testl $2, video_flags - wakeup_code | ||
53 | jz 1f | ||
54 | mov video_mode - wakeup_code, %ax | ||
55 | call mode_set | ||
56 | 1: | ||
57 | |||
58 | # set up page table | ||
59 | movl $swapper_pg_dir-__PAGE_OFFSET, %eax | ||
60 | movl %eax, %cr3 | ||
61 | |||
62 | testl $1, real_efer_save_restore - wakeup_code | ||
63 | jz 4f | ||
64 | # restore efer setting | ||
65 | movl real_save_efer_edx - wakeup_code, %edx | ||
66 | movl real_save_efer_eax - wakeup_code, %eax | ||
67 | mov $0xc0000080, %ecx | ||
68 | wrmsr | ||
69 | 4: | ||
70 | # make sure %cr4 is set correctly (features, etc) | ||
71 | movl real_save_cr4 - wakeup_code, %eax | ||
72 | movl %eax, %cr4 | ||
73 | movw $0xb800, %ax | ||
74 | movw %ax,%fs | ||
75 | movw $0x0e00 + 'i', %fs:(0x12) | ||
76 | |||
77 | # need a gdt | ||
78 | lgdt real_save_gdt - wakeup_code | ||
79 | |||
80 | movl real_save_cr0 - wakeup_code, %eax | ||
81 | movl %eax, %cr0 | ||
82 | jmp 1f | ||
83 | 1: | ||
84 | movw $0x0e00 + 'n', %fs:(0x14) | ||
85 | |||
86 | movl real_magic - wakeup_code, %eax | ||
87 | cmpl $0x12345678, %eax | ||
88 | jne bogus_real_magic | ||
89 | |||
90 | ljmpl $__KERNEL_CS,$wakeup_pmode_return | ||
91 | |||
92 | real_save_gdt: .word 0 | ||
93 | .long 0 | ||
94 | real_save_cr0: .long 0 | ||
95 | real_save_cr3: .long 0 | ||
96 | real_save_cr4: .long 0 | ||
97 | real_magic: .long 0 | ||
98 | video_mode: .long 0 | ||
99 | video_flags: .long 0 | ||
100 | real_efer_save_restore: .long 0 | ||
101 | real_save_efer_edx: .long 0 | ||
102 | real_save_efer_eax: .long 0 | ||
103 | |||
104 | bogus_real_magic: | ||
105 | movw $0x0e00 + 'B', %fs:(0x12) | ||
106 | jmp bogus_real_magic | ||
107 | |||
108 | /* This code uses an extended set of video mode numbers. These include: | ||
109 | * Aliases for standard modes | ||
110 | * NORMAL_VGA (-1) | ||
111 | * EXTENDED_VGA (-2) | ||
112 | * ASK_VGA (-3) | ||
113 | * Video modes numbered by menu position -- NOT RECOMMENDED because of lack | ||
114 | * of compatibility when extending the table. These are between 0x00 and 0xff. | ||
115 | */ | ||
116 | #define VIDEO_FIRST_MENU 0x0000 | ||
117 | |||
118 | /* Standard BIOS video modes (BIOS number + 0x0100) */ | ||
119 | #define VIDEO_FIRST_BIOS 0x0100 | ||
120 | |||
121 | /* VESA BIOS video modes (VESA number + 0x0200) */ | ||
122 | #define VIDEO_FIRST_VESA 0x0200 | ||
123 | |||
124 | /* Video7 special modes (BIOS number + 0x0900) */ | ||
125 | #define VIDEO_FIRST_V7 0x0900 | ||
126 | |||
127 | # Setting of user mode (AX=mode ID) => CF=success | ||
128 | mode_set: | ||
129 | movw %ax, %bx | ||
130 | #if 0 | ||
131 | cmpb $0xff, %ah | ||
132 | jz setalias | ||
133 | |||
134 | testb $VIDEO_RECALC>>8, %ah | ||
135 | jnz _setrec | ||
136 | |||
137 | cmpb $VIDEO_FIRST_RESOLUTION>>8, %ah | ||
138 | jnc setres | ||
139 | |||
140 | cmpb $VIDEO_FIRST_SPECIAL>>8, %ah | ||
141 | jz setspc | ||
142 | |||
143 | cmpb $VIDEO_FIRST_V7>>8, %ah | ||
144 | jz setv7 | ||
145 | #endif | ||
146 | |||
147 | cmpb $VIDEO_FIRST_VESA>>8, %ah | ||
148 | jnc check_vesa | ||
149 | #if 0 | ||
150 | orb %ah, %ah | ||
151 | jz setmenu | ||
152 | #endif | ||
153 | |||
154 | decb %ah | ||
155 | # jz setbios Add bios modes later | ||
156 | |||
157 | setbad: clc | ||
158 | ret | ||
159 | |||
160 | check_vesa: | ||
161 | subb $VIDEO_FIRST_VESA>>8, %bh | ||
162 | orw $0x4000, %bx # Use linear frame buffer | ||
163 | movw $0x4f02, %ax # VESA BIOS mode set call | ||
164 | int $0x10 | ||
165 | cmpw $0x004f, %ax # AL=4f if implemented | ||
166 | jnz _setbad # AH=0 if OK | ||
167 | |||
168 | stc | ||
169 | ret | ||
170 | |||
171 | _setbad: jmp setbad | ||
172 | |||
173 | .code32 | ||
174 | ALIGN | ||
175 | |||
176 | .org 0x800 | ||
177 | wakeup_stack_begin: # Stack grows down | ||
178 | |||
179 | .org 0xff0 # Just below end of page | ||
180 | wakeup_stack: | ||
181 | ENTRY(wakeup_end) | ||
182 | |||
183 | .org 0x1000 | ||
184 | |||
185 | wakeup_pmode_return: | ||
186 | movw $__KERNEL_DS, %ax | ||
187 | movw %ax, %ss | ||
188 | movw %ax, %ds | ||
189 | movw %ax, %es | ||
190 | movw %ax, %fs | ||
191 | movw %ax, %gs | ||
192 | movw $0x0e00 + 'u', 0xb8016 | ||
193 | |||
194 | # reload the gdt, as we need the full 32 bit address | ||
195 | lgdt saved_gdt | ||
196 | lidt saved_idt | ||
197 | lldt saved_ldt | ||
198 | ljmp $(__KERNEL_CS),$1f | ||
199 | 1: | ||
200 | movl %cr3, %eax | ||
201 | movl %eax, %cr3 | ||
202 | wbinvd | ||
203 | |||
204 | # and restore the stack ... but you need gdt for this to work | ||
205 | movl saved_context_esp, %esp | ||
206 | |||
207 | movl %cs:saved_magic, %eax | ||
208 | cmpl $0x12345678, %eax | ||
209 | jne bogus_magic | ||
210 | |||
211 | # jump to place where we left off | ||
212 | movl saved_eip,%eax | ||
213 | jmp *%eax | ||
214 | |||
215 | bogus_magic: | ||
216 | movw $0x0e00 + 'B', 0xb8018 | ||
217 | jmp bogus_magic | ||
218 | |||
219 | |||
220 | ## | ||
221 | # acpi_copy_wakeup_routine | ||
222 | # | ||
223 | # Copy the above routine to low memory. | ||
224 | # | ||
225 | # Parameters: | ||
226 | # %eax: place to copy wakeup routine to | ||
227 | # | ||
228 | # Returned address is location of code in low memory (past data and stack) | ||
229 | # | ||
230 | ENTRY(acpi_copy_wakeup_routine) | ||
231 | |||
232 | sgdt saved_gdt | ||
233 | sidt saved_idt | ||
234 | sldt saved_ldt | ||
235 | str saved_tss | ||
236 | |||
237 | movl nx_enabled, %edx | ||
238 | movl %edx, real_efer_save_restore - wakeup_start (%eax) | ||
239 | testl $1, real_efer_save_restore - wakeup_start (%eax) | ||
240 | jz 2f | ||
241 | # save efer setting | ||
242 | pushl %eax | ||
243 | movl %eax, %ebx | ||
244 | mov $0xc0000080, %ecx | ||
245 | rdmsr | ||
246 | movl %edx, real_save_efer_edx - wakeup_start (%ebx) | ||
247 | movl %eax, real_save_efer_eax - wakeup_start (%ebx) | ||
248 | popl %eax | ||
249 | 2: | ||
250 | |||
251 | movl %cr3, %edx | ||
252 | movl %edx, real_save_cr3 - wakeup_start (%eax) | ||
253 | movl %cr4, %edx | ||
254 | movl %edx, real_save_cr4 - wakeup_start (%eax) | ||
255 | movl %cr0, %edx | ||
256 | movl %edx, real_save_cr0 - wakeup_start (%eax) | ||
257 | sgdt real_save_gdt - wakeup_start (%eax) | ||
258 | |||
259 | movl saved_videomode, %edx | ||
260 | movl %edx, video_mode - wakeup_start (%eax) | ||
261 | movl acpi_video_flags, %edx | ||
262 | movl %edx, video_flags - wakeup_start (%eax) | ||
263 | movl $0x12345678, real_magic - wakeup_start (%eax) | ||
264 | movl $0x12345678, saved_magic | ||
265 | ret | ||
266 | |||
267 | .data | ||
268 | ALIGN | ||
269 | ENTRY(saved_magic) .long 0 | ||
270 | ENTRY(saved_eip) .long 0 | ||
271 | |||
272 | save_registers: | ||
273 | leal 4(%esp), %eax | ||
274 | movl %eax, saved_context_esp | ||
275 | movl %ebx, saved_context_ebx | ||
276 | movl %ebp, saved_context_ebp | ||
277 | movl %esi, saved_context_esi | ||
278 | movl %edi, saved_context_edi | ||
279 | pushfl ; popl saved_context_eflags | ||
280 | |||
281 | movl $ret_point, saved_eip | ||
282 | ret | ||
283 | |||
284 | |||
285 | restore_registers: | ||
286 | movl saved_context_ebp, %ebp | ||
287 | movl saved_context_ebx, %ebx | ||
288 | movl saved_context_esi, %esi | ||
289 | movl saved_context_edi, %edi | ||
290 | pushl saved_context_eflags ; popfl | ||
291 | ret | ||
292 | |||
293 | ENTRY(do_suspend_lowlevel) | ||
294 | call save_processor_state | ||
295 | call save_registers | ||
296 | pushl $3 | ||
297 | call acpi_enter_sleep_state | ||
298 | addl $4, %esp | ||
299 | ret | ||
300 | .p2align 4,,7 | ||
301 | ret_point: | ||
302 | call restore_registers | ||
303 | call restore_processor_state | ||
304 | ret | ||
305 | |||
306 | ENTRY(do_suspend_lowlevel_s4bios) | ||
307 | call save_processor_state | ||
308 | call save_registers | ||
309 | call acpi_enter_sleep_state_s4bios | ||
310 | ret | ||
311 | |||
312 | ALIGN | ||
313 | # saved registers | ||
314 | saved_gdt: .long 0,0 | ||
315 | saved_idt: .long 0,0 | ||
316 | saved_ldt: .long 0 | ||
317 | saved_tss: .long 0 | ||
318 | |||