]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/blob - arch/x86/kernel/acpi/wakeup_32.S
ACPI: suspend: old debugging hacks sneaked back
[linux-2.6-omap-h63xx.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