blob: 39d32484f6f58d9db03f6bfee79ca3f3c87c3fab [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001.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
16ALIGN
17 .align 4096
18ENTRY(wakeup_start)
19wakeup_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
501:
51
52 testl $2, video_flags - wakeup_code
53 jz 1f
54 mov video_mode - wakeup_code, %ax
55 call mode_set
561:
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
694:
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
831:
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
92real_save_gdt: .word 0
93 .long 0
94real_save_cr0: .long 0
95real_save_cr3: .long 0
96real_save_cr4: .long 0
97real_magic: .long 0
98video_mode: .long 0
99video_flags: .long 0
100real_efer_save_restore: .long 0
101real_save_efer_edx: .long 0
102real_save_efer_eax: .long 0
103
104bogus_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
128mode_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
157setbad: clc
158 ret
159
160check_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
177wakeup_stack_begin: # Stack grows down
178
179.org 0xff0 # Just below end of page
180wakeup_stack:
181ENTRY(wakeup_end)
182
183.org 0x1000
184
185wakeup_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
1991:
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
215bogus_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#
230ENTRY(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
2492:
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
268ALIGN
269ENTRY(saved_magic) .long 0
270ENTRY(saved_eip) .long 0
271
272save_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
285restore_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
293ENTRY(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
301ret_point:
302 call restore_registers
303 call restore_processor_state
304 ret
305
306ENTRY(do_suspend_lowlevel_s4bios)
307 call save_processor_state
308 call save_registers
309 call acpi_enter_sleep_state_s4bios
310 ret
311
312ALIGN
313# saved registers
314saved_gdt: .long 0,0
315saved_idt: .long 0,0
316saved_ldt: .long 0
317saved_tss: .long 0
318