Commit | Line | Data |
---|---|---|
1da177e4 LT |
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 | ||
5a60d623 NC |
16 | #define BEEP \ |
17 | inb $97, %al; \ | |
18 | outb %al, $0x80; \ | |
19 | movb $3, %al; \ | |
20 | outb %al, $97; \ | |
21 | outb %al, $0x80; \ | |
22 | movb $-74, %al; \ | |
23 | outb %al, $67; \ | |
24 | outb %al, $0x80; \ | |
25 | movb $-119, %al; \ | |
26 | outb %al, $66; \ | |
27 | outb %al, $0x80; \ | |
28 | movb $15, %al; \ | |
29 | outb %al, $66; | |
30 | ||
1da177e4 LT |
31 | ALIGN |
32 | .align 4096 | |
33 | ENTRY(wakeup_start) | |
34 | wakeup_code: | |
35 | wakeup_code_start = . | |
36 | .code16 | |
37 | ||
38 | movw $0xb800, %ax | |
39 | movw %ax,%fs | |
40 | movw $0x0e00 + 'L', %fs:(0x10) | |
41 | ||
42 | cli | |
43 | cld | |
44 | ||
45 | # setup data segment | |
46 | movw %cs, %ax | |
47 | movw %ax, %ds # Make ds:0 point to wakeup_start | |
48 | movw %ax, %ss | |
5a60d623 | 49 | |
77afcf78 | 50 | testl $4, realmode_flags - wakeup_code |
5a60d623 NC |
51 | jz 1f |
52 | BEEP | |
53 | 1: | |
1da177e4 LT |
54 | mov $(wakeup_stack - wakeup_code), %sp # Private stack is needed for ASUS board |
55 | movw $0x0e00 + 'S', %fs:(0x12) | |
56 | ||
57 | pushl $0 # Kill any dangerous flags | |
58 | popfl | |
59 | ||
60 | movl real_magic - wakeup_code, %eax | |
61 | cmpl $0x12345678, %eax | |
62 | jne bogus_real_magic | |
63 | ||
77afcf78 | 64 | testl $1, realmode_flags - wakeup_code |
1da177e4 LT |
65 | jz 1f |
66 | lcall $0xc000,$3 | |
67 | movw %cs, %ax | |
68 | movw %ax, %ds # Bios might have played with that | |
69 | movw %ax, %ss | |
70 | 1: | |
71 | ||
77afcf78 | 72 | testl $2, realmode_flags - wakeup_code |
1da177e4 LT |
73 | jz 1f |
74 | mov video_mode - wakeup_code, %ax | |
75 | call mode_set | |
76 | 1: | |
77 | ||
78 | # set up page table | |
55b2355e | 79 | movl $swsusp_pg_dir-__PAGE_OFFSET, %eax |
1da177e4 LT |
80 | movl %eax, %cr3 |
81 | ||
82 | testl $1, real_efer_save_restore - wakeup_code | |
83 | jz 4f | |
84 | # restore efer setting | |
85 | movl real_save_efer_edx - wakeup_code, %edx | |
86 | movl real_save_efer_eax - wakeup_code, %eax | |
87 | mov $0xc0000080, %ecx | |
88 | wrmsr | |
89 | 4: | |
90 | # make sure %cr4 is set correctly (features, etc) | |
91 | movl real_save_cr4 - wakeup_code, %eax | |
92 | movl %eax, %cr4 | |
93 | movw $0xb800, %ax | |
94 | movw %ax,%fs | |
95 | movw $0x0e00 + 'i', %fs:(0x12) | |
96 | ||
9d943775 NZ |
97 | # need a gdt -- use lgdtl to force 32-bit operands, in case |
98 | # the GDT is located past 16 megabytes. | |
99 | lgdtl real_save_gdt - wakeup_code | |
1da177e4 LT |
100 | |
101 | movl real_save_cr0 - wakeup_code, %eax | |
102 | movl %eax, %cr0 | |
103 | jmp 1f | |
104 | 1: | |
105 | movw $0x0e00 + 'n', %fs:(0x14) | |
106 | ||
107 | movl real_magic - wakeup_code, %eax | |
108 | cmpl $0x12345678, %eax | |
109 | jne bogus_real_magic | |
110 | ||
77afcf78 | 111 | testl $8, realmode_flags - wakeup_code |
5a60d623 NC |
112 | jz 1f |
113 | BEEP | |
114 | 1: | |
77afcf78 | 115 | ljmpl $__KERNEL_CS, $wakeup_pmode_return |
1da177e4 LT |
116 | |
117 | real_save_gdt: .word 0 | |
118 | .long 0 | |
119 | real_save_cr0: .long 0 | |
120 | real_save_cr3: .long 0 | |
121 | real_save_cr4: .long 0 | |
122 | real_magic: .long 0 | |
123 | video_mode: .long 0 | |
77afcf78 | 124 | realmode_flags: .long 0 |
5a60d623 | 125 | beep_flags: .long 0 |
1da177e4 LT |
126 | real_efer_save_restore: .long 0 |
127 | real_save_efer_edx: .long 0 | |
128 | real_save_efer_eax: .long 0 | |
129 | ||
130 | bogus_real_magic: | |
131 | movw $0x0e00 + 'B', %fs:(0x12) | |
132 | jmp bogus_real_magic | |
133 | ||
134 | /* This code uses an extended set of video mode numbers. These include: | |
135 | * Aliases for standard modes | |
136 | * NORMAL_VGA (-1) | |
137 | * EXTENDED_VGA (-2) | |
138 | * ASK_VGA (-3) | |
139 | * Video modes numbered by menu position -- NOT RECOMMENDED because of lack | |
140 | * of compatibility when extending the table. These are between 0x00 and 0xff. | |
141 | */ | |
142 | #define VIDEO_FIRST_MENU 0x0000 | |
143 | ||
144 | /* Standard BIOS video modes (BIOS number + 0x0100) */ | |
145 | #define VIDEO_FIRST_BIOS 0x0100 | |
146 | ||
147 | /* VESA BIOS video modes (VESA number + 0x0200) */ | |
148 | #define VIDEO_FIRST_VESA 0x0200 | |
149 | ||
150 | /* Video7 special modes (BIOS number + 0x0900) */ | |
151 | #define VIDEO_FIRST_V7 0x0900 | |
152 | ||
153 | # Setting of user mode (AX=mode ID) => CF=success | |
154 | mode_set: | |
155 | movw %ax, %bx | |
156 | #if 0 | |
157 | cmpb $0xff, %ah | |
158 | jz setalias | |
159 | ||
160 | testb $VIDEO_RECALC>>8, %ah | |
161 | jnz _setrec | |
162 | ||
163 | cmpb $VIDEO_FIRST_RESOLUTION>>8, %ah | |
164 | jnc setres | |
165 | ||
166 | cmpb $VIDEO_FIRST_SPECIAL>>8, %ah | |
167 | jz setspc | |
168 | ||
169 | cmpb $VIDEO_FIRST_V7>>8, %ah | |
170 | jz setv7 | |
171 | #endif | |
172 | ||
173 | cmpb $VIDEO_FIRST_VESA>>8, %ah | |
174 | jnc check_vesa | |
175 | #if 0 | |
176 | orb %ah, %ah | |
177 | jz setmenu | |
178 | #endif | |
179 | ||
180 | decb %ah | |
181 | # jz setbios Add bios modes later | |
182 | ||
183 | setbad: clc | |
184 | ret | |
185 | ||
186 | check_vesa: | |
187 | subb $VIDEO_FIRST_VESA>>8, %bh | |
188 | orw $0x4000, %bx # Use linear frame buffer | |
189 | movw $0x4f02, %ax # VESA BIOS mode set call | |
190 | int $0x10 | |
191 | cmpw $0x004f, %ax # AL=4f if implemented | |
192 | jnz _setbad # AH=0 if OK | |
193 | ||
194 | stc | |
195 | ret | |
196 | ||
197 | _setbad: jmp setbad | |
198 | ||
199 | .code32 | |
200 | ALIGN | |
201 | ||
202 | .org 0x800 | |
203 | wakeup_stack_begin: # Stack grows down | |
204 | ||
205 | .org 0xff0 # Just below end of page | |
206 | wakeup_stack: | |
207 | ENTRY(wakeup_end) | |
208 | ||
209 | .org 0x1000 | |
210 | ||
211 | wakeup_pmode_return: | |
212 | movw $__KERNEL_DS, %ax | |
213 | movw %ax, %ss | |
214 | movw %ax, %ds | |
215 | movw %ax, %es | |
216 | movw %ax, %fs | |
217 | movw %ax, %gs | |
218 | movw $0x0e00 + 'u', 0xb8016 | |
219 | ||
220 | # reload the gdt, as we need the full 32 bit address | |
221 | lgdt saved_gdt | |
222 | lidt saved_idt | |
223 | lldt saved_ldt | |
224 | ljmp $(__KERNEL_CS),$1f | |
225 | 1: | |
226 | movl %cr3, %eax | |
227 | movl %eax, %cr3 | |
228 | wbinvd | |
229 | ||
230 | # and restore the stack ... but you need gdt for this to work | |
231 | movl saved_context_esp, %esp | |
232 | ||
233 | movl %cs:saved_magic, %eax | |
234 | cmpl $0x12345678, %eax | |
235 | jne bogus_magic | |
236 | ||
237 | # jump to place where we left off | |
238 | movl saved_eip,%eax | |
239 | jmp *%eax | |
240 | ||
241 | bogus_magic: | |
242 | movw $0x0e00 + 'B', 0xb8018 | |
243 | jmp bogus_magic | |
244 | ||
245 | ||
246 | ## | |
247 | # acpi_copy_wakeup_routine | |
248 | # | |
249 | # Copy the above routine to low memory. | |
250 | # | |
251 | # Parameters: | |
252 | # %eax: place to copy wakeup routine to | |
253 | # | |
254 | # Returned address is location of code in low memory (past data and stack) | |
255 | # | |
256 | ENTRY(acpi_copy_wakeup_routine) | |
257 | ||
c8cbee61 | 258 | pushl %ebx |
1da177e4 LT |
259 | sgdt saved_gdt |
260 | sidt saved_idt | |
261 | sldt saved_ldt | |
262 | str saved_tss | |
263 | ||
264 | movl nx_enabled, %edx | |
265 | movl %edx, real_efer_save_restore - wakeup_start (%eax) | |
266 | testl $1, real_efer_save_restore - wakeup_start (%eax) | |
267 | jz 2f | |
268 | # save efer setting | |
269 | pushl %eax | |
270 | movl %eax, %ebx | |
271 | mov $0xc0000080, %ecx | |
272 | rdmsr | |
273 | movl %edx, real_save_efer_edx - wakeup_start (%ebx) | |
274 | movl %eax, real_save_efer_eax - wakeup_start (%ebx) | |
275 | popl %eax | |
276 | 2: | |
277 | ||
278 | movl %cr3, %edx | |
279 | movl %edx, real_save_cr3 - wakeup_start (%eax) | |
280 | movl %cr4, %edx | |
281 | movl %edx, real_save_cr4 - wakeup_start (%eax) | |
282 | movl %cr0, %edx | |
283 | movl %edx, real_save_cr0 - wakeup_start (%eax) | |
284 | sgdt real_save_gdt - wakeup_start (%eax) | |
285 | ||
286 | movl saved_videomode, %edx | |
287 | movl %edx, video_mode - wakeup_start (%eax) | |
77afcf78 PM |
288 | movl acpi_realmode_flags, %edx |
289 | movl %edx, realmode_flags - wakeup_start (%eax) | |
1da177e4 LT |
290 | movl $0x12345678, real_magic - wakeup_start (%eax) |
291 | movl $0x12345678, saved_magic | |
c8cbee61 | 292 | popl %ebx |
1da177e4 LT |
293 | ret |
294 | ||
1da177e4 LT |
295 | save_registers: |
296 | leal 4(%esp), %eax | |
297 | movl %eax, saved_context_esp | |
298 | movl %ebx, saved_context_ebx | |
299 | movl %ebp, saved_context_ebp | |
300 | movl %esi, saved_context_esi | |
301 | movl %edi, saved_context_edi | |
302 | pushfl ; popl saved_context_eflags | |
303 | ||
304 | movl $ret_point, saved_eip | |
305 | ret | |
306 | ||
307 | ||
308 | restore_registers: | |
309 | movl saved_context_ebp, %ebp | |
310 | movl saved_context_ebx, %ebx | |
311 | movl saved_context_esi, %esi | |
312 | movl saved_context_edi, %edi | |
313 | pushl saved_context_eflags ; popfl | |
314 | ret | |
315 | ||
316 | ENTRY(do_suspend_lowlevel) | |
317 | call save_processor_state | |
318 | call save_registers | |
319 | pushl $3 | |
320 | call acpi_enter_sleep_state | |
321 | addl $4, %esp | |
4e6e6504 WM |
322 | |
323 | # In case of S3 failure, we'll emerge here. Jump | |
324 | # to ret_point to recover | |
325 | jmp ret_point | |
1da177e4 LT |
326 | .p2align 4,,7 |
327 | ret_point: | |
328 | call restore_registers | |
329 | call restore_processor_state | |
330 | ret | |
331 | ||
daacf8bc | 332 | .data |
1da177e4 | 333 | ALIGN |
daacf8bc SL |
334 | ENTRY(saved_magic) .long 0 |
335 | ENTRY(saved_eip) .long 0 | |
336 | ||
1da177e4 LT |
337 | # saved registers |
338 | saved_gdt: .long 0,0 | |
339 | saved_idt: .long 0,0 | |
340 | saved_ldt: .long 0 | |
341 | saved_tss: .long 0 | |
342 |