patch-2_6_7-vs1_9_1_12
[linux-2.6.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 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         # make sure %cr4 is set correctly (features, etc)
63         movl    real_save_cr4 - wakeup_code, %eax
64         movl    %eax, %cr4
65         movw    $0xb800, %ax
66         movw    %ax,%fs
67         movw    $0x0e00 + 'i', %fs:(0x12)
68         
69         # need a gdt
70         lgdt    real_save_gdt - wakeup_code
71
72         movl    real_save_cr0 - wakeup_code, %eax
73         movl    %eax, %cr0
74         jmp 1f
75 1:
76         movw    $0x0e00 + 'n', %fs:(0x14)
77
78         movl    real_magic - wakeup_code, %eax
79         cmpl    $0x12345678, %eax
80         jne     bogus_real_magic
81
82         ljmpl   $__KERNEL_CS,$wakeup_pmode_return
83
84 real_save_gdt:  .word 0
85                 .long 0
86 real_save_cr0:  .long 0
87 real_save_cr3:  .long 0
88 real_save_cr4:  .long 0
89 real_magic:     .long 0
90 video_mode:     .long 0
91 video_flags:    .long 0
92
93 bogus_real_magic:
94         movw    $0x0e00 + 'B', %fs:(0x12)
95         jmp bogus_real_magic
96
97 /* This code uses an extended set of video mode numbers. These include:
98  * Aliases for standard modes
99  *      NORMAL_VGA (-1)
100  *      EXTENDED_VGA (-2)
101  *      ASK_VGA (-3)
102  * Video modes numbered by menu position -- NOT RECOMMENDED because of lack
103  * of compatibility when extending the table. These are between 0x00 and 0xff.
104  */
105 #define VIDEO_FIRST_MENU 0x0000
106
107 /* Standard BIOS video modes (BIOS number + 0x0100) */
108 #define VIDEO_FIRST_BIOS 0x0100
109
110 /* VESA BIOS video modes (VESA number + 0x0200) */
111 #define VIDEO_FIRST_VESA 0x0200
112
113 /* Video7 special modes (BIOS number + 0x0900) */
114 #define VIDEO_FIRST_V7 0x0900
115
116 # Setting of user mode (AX=mode ID) => CF=success
117 mode_set:
118         movw    %ax, %bx
119 #if 0
120         cmpb    $0xff, %ah
121         jz      setalias
122
123         testb   $VIDEO_RECALC>>8, %ah
124         jnz     _setrec
125
126         cmpb    $VIDEO_FIRST_RESOLUTION>>8, %ah
127         jnc     setres
128         
129         cmpb    $VIDEO_FIRST_SPECIAL>>8, %ah
130         jz      setspc
131
132         cmpb    $VIDEO_FIRST_V7>>8, %ah
133         jz      setv7
134 #endif
135         
136         cmpb    $VIDEO_FIRST_VESA>>8, %ah
137         jnc     check_vesa
138 #if 0   
139         orb     %ah, %ah
140         jz      setmenu
141 #endif
142         
143         decb    %ah
144 #       jz      setbios                           Add bios modes later
145
146 setbad: clc
147         ret
148
149 check_vesa:
150         subb    $VIDEO_FIRST_VESA>>8, %bh
151         orw     $0x4000, %bx                    # Use linear frame buffer
152         movw    $0x4f02, %ax                    # VESA BIOS mode set call
153         int     $0x10
154         cmpw    $0x004f, %ax                    # AL=4f if implemented
155         jnz     _setbad                         # AH=0 if OK
156
157         stc
158         ret
159
160 _setbad: jmp setbad
161
162         .code32
163         ALIGN
164
165 .org    0x800
166 wakeup_stack_begin:     # Stack grows down
167
168 .org    0xff0           # Just below end of page
169 wakeup_stack:
170 ENTRY(wakeup_end)
171         
172 .org    0x1000
173
174 wakeup_pmode_return:
175         movw    $__KERNEL_DS, %ax
176         movw    %ax, %ss
177         movw    %ax, %ds
178         movw    %ax, %es
179         movw    %ax, %fs
180         movw    %ax, %gs
181         movw    $0x0e00 + 'u', 0xb8016
182
183         # reload the gdt, as we need the full 32 bit address
184         lgdt    saved_gdt
185         lidt    saved_idt
186         lldt    saved_ldt
187         ljmp    $(__KERNEL_CS),$1f
188 1:
189         movl    %cr3, %eax
190         movl    %eax, %cr3
191         wbinvd
192
193         # and restore the stack ... but you need gdt for this to work
194         movl    saved_context_esp, %esp
195
196         movl    %cs:saved_magic, %eax
197         cmpl    $0x12345678, %eax
198         jne     bogus_magic
199
200         # jump to place where we left off
201         movl    saved_eip,%eax
202         jmp     *%eax
203
204 bogus_magic:
205         movw    $0x0e00 + 'B', 0xb8018
206         jmp     bogus_magic
207
208
209 ##
210 # acpi_copy_wakeup_routine
211 #
212 # Copy the above routine to low memory.
213 #
214 # Parameters:
215 # %eax: place to copy wakeup routine to
216 #
217 # Returned address is location of code in low memory (past data and stack)
218 #
219 ENTRY(acpi_copy_wakeup_routine)
220
221         sgdt    saved_gdt
222         sidt    saved_idt
223         sldt    saved_ldt
224         str     saved_tss
225
226         movl    %cr3, %edx
227         movl    %edx, real_save_cr3 - wakeup_start (%eax)
228         movl    %cr4, %edx
229         movl    %edx, real_save_cr4 - wakeup_start (%eax)
230         movl    %cr0, %edx
231         movl    %edx, real_save_cr0 - wakeup_start (%eax)
232         sgdt    real_save_gdt - wakeup_start (%eax)
233
234         movl    saved_videomode, %edx
235         movl    %edx, video_mode - wakeup_start (%eax)
236         movl    acpi_video_flags, %edx
237         movl    %edx, video_flags - wakeup_start (%eax)
238         movl    $0x12345678, real_magic - wakeup_start (%eax)
239         movl    $0x12345678, saved_magic
240         ret
241
242 .data
243 ALIGN
244 ENTRY(saved_magic)      .long   0
245 ENTRY(saved_eip)        .long   0
246
247 save_registers:
248         leal    4(%esp), %eax
249         movl    %eax, saved_context_esp
250         movl %ebx, saved_context_ebx
251         movl %ebp, saved_context_ebp
252         movl %esi, saved_context_esi
253         movl %edi, saved_context_edi
254         pushfl ; popl saved_context_eflags
255
256         movl $ret_point,saved_eip
257         ret
258
259
260 restore_registers:
261         movl saved_context_ebp, %ebp
262         movl saved_context_ebx, %ebx
263         movl saved_context_esi, %esi
264         movl saved_context_edi, %edi
265         pushl saved_context_eflags ; popfl
266         ret     
267
268 ENTRY(do_suspend_lowlevel)
269         call    save_processor_state
270         call    save_registers
271         pushl   $3
272         call    acpi_enter_sleep_state
273         addl    $4,%esp
274         ret
275         .p2align 4,,7
276 ret_point:
277         call    restore_registers
278         call    restore_processor_state
279         ret
280
281 ENTRY(do_suspend_lowlevel_s4bios)
282         call save_processor_state
283         call save_registers
284         call acpi_enter_sleep_state_s4bios
285         ret
286
287 ALIGN
288 # saved registers
289 saved_gdt:      .long   0,0
290 saved_idt:      .long   0,0
291 saved_ldt:      .long   0
292 saved_tss:      .long   0
293