Linux 2.6.25-rc4
[linux-2.6/next.git] / arch / x86 / kernel / acpi / wakeup_32.S
blobf53e3277f8e500512d1c86a3aa9c2b718715a6f3
1         .section .text.page_aligned
2 #include <linux/linkage.h>
3 #include <asm/segment.h>
4 #include <asm/page.h>
7 # wakeup_code runs in real mode, and at unknown address (determined at run-time).
8 # Therefore it must only use relative jumps/calls. 
10 # Do we need to deal with A20? It is okay: ACPI specs says A20 must be enabled
12 # If physical address of wakeup_code is 0x12345, BIOS should call us with
13 # cs = 0x1234, eip = 0x05
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;
31 ALIGN
32         .align  4096
33 ENTRY(wakeup_start)
34 wakeup_code:
35         wakeup_code_start = .
36         .code16
38         cli
39         cld
41         # setup data segment
42         movw    %cs, %ax
43         movw    %ax, %ds                                        # Make ds:0 point to wakeup_start
44         movw    %ax, %ss
46         testl   $4, realmode_flags - wakeup_code
47         jz      1f
48         BEEP
50         mov     $(wakeup_stack - wakeup_code), %sp              # Private stack is needed for ASUS board
52         pushl   $0                                              # Kill any dangerous flags
53         popfl
55         movl    real_magic - wakeup_code, %eax
56         cmpl    $0x12345678, %eax
57         jne     bogus_real_magic
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
67         testl   $2, realmode_flags - wakeup_code
68         jz      1f
69         mov     video_mode - wakeup_code, %ax
70         call    mode_set
73         # set up page table
74         movl    $swsusp_pg_dir-__PAGE_OFFSET, %eax
75         movl    %eax, %cr3
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
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
93         movl    real_save_cr0 - wakeup_code, %eax
94         movl    %eax, %cr0
95         jmp 1f
97         movl    real_magic - wakeup_code, %eax
98         cmpl    $0x12345678, %eax
99         jne     bogus_real_magic
101         testl   $8, realmode_flags - wakeup_code
102         jz      1f
103         BEEP
105         ljmpl   $__KERNEL_CS, $wakeup_pmode_return
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
119 bogus_real_magic:
120         jmp bogus_real_magic
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
132 /* Standard BIOS video modes (BIOS number + 0x0100) */
133 #define VIDEO_FIRST_BIOS 0x0100
135 /* VESA BIOS video modes (VESA number + 0x0200) */
136 #define VIDEO_FIRST_VESA 0x0200
138 /* Video7 special modes (BIOS number + 0x0900) */
139 #define VIDEO_FIRST_V7 0x0900
141 # Setting of user mode (AX=mode ID) => CF=success
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
152 setbad:
153         clc
154         ret
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
163         stc
164         ret
166         .code32
167         ALIGN
169 .org    0x800
170 wakeup_stack_begin:     # Stack grows down
172 .org    0xff0           # Just below end of page
173 wakeup_stack:
174 ENTRY(wakeup_end)
175         
176 .org    0x1000
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
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
192         movl    %cr3, %eax
193         movl    %eax, %cr3
194         wbinvd
196         # and restore the stack ... but you need gdt for this to work
197         movl    saved_context_esp, %esp
199         movl    %cs:saved_magic, %eax
200         cmpl    $0x12345678, %eax
201         jne     bogus_magic
203         # jump to place where we left off
204         movl    saved_eip,%eax
205         jmp     *%eax
207 bogus_magic:
208         jmp     bogus_magic
212 # acpi_copy_wakeup_routine
214 # Copy the above routine to low memory.
216 # Parameters:
217 # %eax: place to copy wakeup routine to
219 # Returned address is location of code in low memory (past data and stack)
221 ENTRY(acpi_copy_wakeup_routine)
223         pushl   %ebx
224         sgdt    saved_gdt
225         sidt    saved_idt
226         sldt    saved_ldt
227         str     saved_tss
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
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)
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
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
269         movl $ret_point, saved_eip
270         ret
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     
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
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
297 .data
298 ALIGN
299 ENTRY(saved_magic)      .long   0
300 ENTRY(saved_eip)        .long   0
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