b4e2ec3c39284308d2f1111327474902169b6281
[GitHub/MotorolaMobilityLLC/kernel-slsi.git] / arch / i386 / kernel / acpi / wakeup.S
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 #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
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
49
50 testl $1, beep_flags - wakeup_code
51 jz 1f
52 BEEP
53 1:
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
64 testl $1, video_flags - wakeup_code
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
72 testl $2, video_flags - wakeup_code
73 jz 1f
74 mov video_mode - wakeup_code, %ax
75 call mode_set
76 1:
77
78 # set up page table
79 movl $swsusp_pg_dir-__PAGE_OFFSET, %eax
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
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
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
111 testl $2, beep_flags - wakeup_code
112 jz 1f
113 BEEP
114 1:
115 ljmpl $__KERNEL_CS,$wakeup_pmode_return
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
124 video_flags: .long 0
125 beep_flags: .long 0
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
258 pushl %ebx
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)
288 movl acpi_video_flags, %edx
289 movl %edx, video_flags - wakeup_start (%eax)
290 movl s2ram_beep, %edx
291 movl %edx, beep_flags - wakeup_start (%eax)
292 movl $0x12345678, real_magic - wakeup_start (%eax)
293 movl $0x12345678, saved_magic
294 popl %ebx
295 ret
296
297 save_registers:
298 leal 4(%esp), %eax
299 movl %eax, saved_context_esp
300 movl %ebx, saved_context_ebx
301 movl %ebp, saved_context_ebp
302 movl %esi, saved_context_esi
303 movl %edi, saved_context_edi
304 pushfl ; popl saved_context_eflags
305
306 movl $ret_point, saved_eip
307 ret
308
309
310 restore_registers:
311 movl saved_context_ebp, %ebp
312 movl saved_context_ebx, %ebx
313 movl saved_context_esi, %esi
314 movl saved_context_edi, %edi
315 pushl saved_context_eflags ; popfl
316 ret
317
318 ENTRY(do_suspend_lowlevel)
319 call save_processor_state
320 call save_registers
321 pushl $3
322 call acpi_enter_sleep_state
323 addl $4, %esp
324
325 # In case of S3 failure, we'll emerge here. Jump
326 # to ret_point to recover
327 jmp ret_point
328 .p2align 4,,7
329 ret_point:
330 call restore_registers
331 call restore_processor_state
332 ret
333
334 .data
335 ALIGN
336 ENTRY(saved_magic) .long 0
337 ENTRY(saved_eip) .long 0
338
339 # saved registers
340 saved_gdt: .long 0,0
341 saved_idt: .long 0,0
342 saved_ldt: .long 0
343 saved_tss: .long 0
344