Merge git://git.kernel.org/pub/scm/linux/kernel/git/herbert/crypto-2.6
[deliverable/linux.git] / arch / x86 / kernel / acpi / wakeup_32.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 cli
39 cld
40
41 # setup data segment
42 movw %cs, %ax
43 movw %ax, %ds # Make ds:0 point to wakeup_start
44 movw %ax, %ss
45
46 testl $4, realmode_flags - wakeup_code
47 jz 1f
48 BEEP
49 1:
50 mov $(wakeup_stack - wakeup_code), %sp # Private stack is needed for ASUS board
51
52 pushl $0 # Kill any dangerous flags
53 popfl
54
55 movl real_magic - wakeup_code, %eax
56 cmpl $0x12345678, %eax
57 jne bogus_real_magic
58
59 testl $1, realmode_flags - wakeup_code
60 jz 1f
61 lcall $0xc000,$3
62 movw %cs, %ax
63 movw %ax, %ds # Bios might have played with that
64 movw %ax, %ss
65 1:
66
67 testl $2, realmode_flags - wakeup_code
68 jz 1f
69 mov video_mode - wakeup_code, %ax
70 call mode_set
71 1:
72
73 # set up page table
74 movl $swsusp_pg_dir-__PAGE_OFFSET, %eax
75 movl %eax, %cr3
76
77 testl $1, real_efer_save_restore - wakeup_code
78 jz 4f
79 # restore efer setting
80 movl real_save_efer_edx - wakeup_code, %edx
81 movl real_save_efer_eax - wakeup_code, %eax
82 mov $0xc0000080, %ecx
83 wrmsr
84 4:
85 # make sure %cr4 is set correctly (features, etc)
86 movl real_save_cr4 - wakeup_code, %eax
87 movl %eax, %cr4
88
89 # need a gdt -- use lgdtl to force 32-bit operands, in case
90 # the GDT is located past 16 megabytes.
91 lgdtl real_save_gdt - wakeup_code
92
93 movl real_save_cr0 - wakeup_code, %eax
94 movl %eax, %cr0
95 jmp 1f
96 1:
97 movl real_magic - wakeup_code, %eax
98 cmpl $0x12345678, %eax
99 jne bogus_real_magic
100
101 testl $8, realmode_flags - wakeup_code
102 jz 1f
103 BEEP
104 1:
105 ljmpl $__KERNEL_CS, $wakeup_pmode_return
106
107 real_save_gdt: .word 0
108 .long 0
109 real_save_cr0: .long 0
110 real_save_cr3: .long 0
111 real_save_cr4: .long 0
112 real_magic: .long 0
113 video_mode: .long 0
114 realmode_flags: .long 0
115 real_efer_save_restore: .long 0
116 real_save_efer_edx: .long 0
117 real_save_efer_eax: .long 0
118
119 bogus_real_magic:
120 jmp bogus_real_magic
121
122 /* This code uses an extended set of video mode numbers. These include:
123 * Aliases for standard modes
124 * NORMAL_VGA (-1)
125 * EXTENDED_VGA (-2)
126 * ASK_VGA (-3)
127 * Video modes numbered by menu position -- NOT RECOMMENDED because of lack
128 * of compatibility when extending the table. These are between 0x00 and 0xff.
129 */
130 #define VIDEO_FIRST_MENU 0x0000
131
132 /* Standard BIOS video modes (BIOS number + 0x0100) */
133 #define VIDEO_FIRST_BIOS 0x0100
134
135 /* VESA BIOS video modes (VESA number + 0x0200) */
136 #define VIDEO_FIRST_VESA 0x0200
137
138 /* Video7 special modes (BIOS number + 0x0900) */
139 #define VIDEO_FIRST_V7 0x0900
140
141 # Setting of user mode (AX=mode ID) => CF=success
142
143 # For now, we only handle VESA modes (0x0200..0x03ff). To handle other
144 # modes, we should probably compile in the video code from the boot
145 # directory.
146 mode_set:
147 movw %ax, %bx
148 subb $VIDEO_FIRST_VESA>>8, %bh
149 cmpb $2, %bh
150 jb check_vesa
151
152 setbad:
153 clc
154 ret
155
156 check_vesa:
157 orw $0x4000, %bx # Use linear frame buffer
158 movw $0x4f02, %ax # VESA BIOS mode set call
159 int $0x10
160 cmpw $0x004f, %ax # AL=4f if implemented
161 jnz setbad # AH=0 if OK
162
163 stc
164 ret
165
166 .code32
167 ALIGN
168
169 .org 0x800
170 wakeup_stack_begin: # Stack grows down
171
172 .org 0xff0 # Just below end of page
173 wakeup_stack:
174 ENTRY(wakeup_end)
175
176 .org 0x1000
177
178 wakeup_pmode_return:
179 movw $__KERNEL_DS, %ax
180 movw %ax, %ss
181 movw %ax, %ds
182 movw %ax, %es
183 movw %ax, %fs
184 movw %ax, %gs
185
186 # reload the gdt, as we need the full 32 bit address
187 lgdt saved_gdt
188 lidt saved_idt
189 lldt saved_ldt
190 ljmp $(__KERNEL_CS),$1f
191 1:
192 movl %cr3, %eax
193 movl %eax, %cr3
194 wbinvd
195
196 # and restore the stack ... but you need gdt for this to work
197 movl saved_context_esp, %esp
198
199 movl %cs:saved_magic, %eax
200 cmpl $0x12345678, %eax
201 jne bogus_magic
202
203 # jump to place where we left off
204 movl saved_eip,%eax
205 jmp *%eax
206
207 bogus_magic:
208 jmp bogus_magic
209
210
211 ##
212 # acpi_copy_wakeup_routine
213 #
214 # Copy the above routine to low memory.
215 #
216 # Parameters:
217 # %eax: place to copy wakeup routine to
218 #
219 # Returned address is location of code in low memory (past data and stack)
220 #
221 ENTRY(acpi_copy_wakeup_routine)
222
223 pushl %ebx
224 sgdt saved_gdt
225 sidt saved_idt
226 sldt saved_ldt
227 str saved_tss
228
229 movl nx_enabled, %edx
230 movl %edx, real_efer_save_restore - wakeup_start (%eax)
231 testl $1, real_efer_save_restore - wakeup_start (%eax)
232 jz 2f
233 # save efer setting
234 pushl %eax
235 movl %eax, %ebx
236 mov $0xc0000080, %ecx
237 rdmsr
238 movl %edx, real_save_efer_edx - wakeup_start (%ebx)
239 movl %eax, real_save_efer_eax - wakeup_start (%ebx)
240 popl %eax
241 2:
242
243 movl %cr3, %edx
244 movl %edx, real_save_cr3 - wakeup_start (%eax)
245 movl %cr4, %edx
246 movl %edx, real_save_cr4 - wakeup_start (%eax)
247 movl %cr0, %edx
248 movl %edx, real_save_cr0 - wakeup_start (%eax)
249 sgdt real_save_gdt - wakeup_start (%eax)
250
251 movl saved_videomode, %edx
252 movl %edx, video_mode - wakeup_start (%eax)
253 movl acpi_realmode_flags, %edx
254 movl %edx, realmode_flags - wakeup_start (%eax)
255 movl $0x12345678, real_magic - wakeup_start (%eax)
256 movl $0x12345678, saved_magic
257 popl %ebx
258 ret
259
260 save_registers:
261 leal 4(%esp), %eax
262 movl %eax, saved_context_esp
263 movl %ebx, saved_context_ebx
264 movl %ebp, saved_context_ebp
265 movl %esi, saved_context_esi
266 movl %edi, saved_context_edi
267 pushfl ; popl saved_context_eflags
268
269 movl $ret_point, saved_eip
270 ret
271
272
273 restore_registers:
274 movl saved_context_ebp, %ebp
275 movl saved_context_ebx, %ebx
276 movl saved_context_esi, %esi
277 movl saved_context_edi, %edi
278 pushl saved_context_eflags ; popfl
279 ret
280
281 ENTRY(do_suspend_lowlevel)
282 call save_processor_state
283 call save_registers
284 pushl $3
285 call acpi_enter_sleep_state
286 addl $4, %esp
287
288 # In case of S3 failure, we'll emerge here. Jump
289 # to ret_point to recover
290 jmp ret_point
291 .p2align 4,,7
292 ret_point:
293 call restore_registers
294 call restore_processor_state
295 ret
296
297 .data
298 ALIGN
299 ENTRY(saved_magic) .long 0
300 ENTRY(saved_eip) .long 0
301
302 # saved registers
303 saved_gdt: .long 0,0
304 saved_idt: .long 0,0
305 saved_ldt: .long 0
306 saved_tss: .long 0
307
This page took 0.058186 seconds and 6 git commands to generate.