Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input
[pandora-kernel.git] / arch / x86 / kernel / acpi / wakeup_64.S
1 .text
2 #include <linux/linkage.h>
3 #include <asm/segment.h>
4 #include <asm/pgtable.h>
5 #include <asm/page.h>
6 #include <asm/msr.h>
7
8 # Copyright 2003 Pavel Machek <pavel@suse.cz>, distribute under GPLv2
9 #
10 # wakeup_code runs in real mode, and at unknown address (determined at run-time).
11 # Therefore it must only use relative jumps/calls. 
12 #
13 # Do we need to deal with A20? It is okay: ACPI specs says A20 must be enabled
14 #
15 # If physical address of wakeup_code is 0x12345, BIOS should call us with
16 # cs = 0x1234, eip = 0x05
17 #
18
19 #define BEEP \
20         inb     $97, %al;       \
21         outb    %al, $0x80;     \
22         movb    $3, %al;        \
23         outb    %al, $97;       \
24         outb    %al, $0x80;     \
25         movb    $-74, %al;      \
26         outb    %al, $67;       \
27         outb    %al, $0x80;     \
28         movb    $-119, %al;     \
29         outb    %al, $66;       \
30         outb    %al, $0x80;     \
31         movb    $15, %al;       \
32         outb    %al, $66;
33
34
35 ALIGN
36         .align  16
37 ENTRY(wakeup_start)
38 wakeup_code:
39         wakeup_code_start = .
40         .code16
41
42 # Running in *copy* of this code, somewhere in low 1MB.
43
44         cli
45         cld
46         # setup data segment
47         movw    %cs, %ax
48         movw    %ax, %ds                # Make ds:0 point to wakeup_start
49         movw    %ax, %ss
50
51         # Data segment must be set up before we can see whether to beep.
52         testl   $4, realmode_flags - wakeup_code
53         jz      1f
54         BEEP
55 1:
56
57                                         # Private stack is needed for ASUS board
58         mov     $(wakeup_stack - wakeup_code), %sp
59
60         pushl   $0                      # Kill any dangerous flags
61         popfl
62
63         movl    real_magic - wakeup_code, %eax
64         cmpl    $0x12345678, %eax
65         jne     bogus_real_magic
66
67         testl   $1, realmode_flags - wakeup_code
68         jz      1f
69         lcall   $0xc000,$3
70         movw    %cs, %ax
71         movw    %ax, %ds                # Bios might have played with that
72         movw    %ax, %ss
73 1:
74
75         testl   $2, realmode_flags - wakeup_code
76         jz      1f
77         mov     video_mode - wakeup_code, %ax
78         call    mode_set
79 1:
80
81         mov     %ds, %ax                        # Find 32bit wakeup_code addr
82         movzx   %ax, %esi                       # (Convert %ds:gdt to a liner ptr)
83         shll    $4, %esi
84                                                 # Fix up the vectors
85         addl    %esi, wakeup_32_vector - wakeup_code
86         addl    %esi, wakeup_long64_vector - wakeup_code
87         addl    %esi, gdt_48a + 2 - wakeup_code # Fixup the gdt pointer
88
89         lidtl   %ds:idt_48a - wakeup_code
90         lgdtl   %ds:gdt_48a - wakeup_code       # load gdt with whatever is
91                                                 # appropriate
92
93         movl    $1, %eax                        # protected mode (PE) bit
94         lmsw    %ax                             # This is it!
95         jmp     1f
96 1:
97
98         ljmpl   *(wakeup_32_vector - wakeup_code)
99
100         .balign 4
101 wakeup_32_vector:
102         .long   wakeup_32 - wakeup_code
103         .word   __KERNEL32_CS, 0
104
105         .code32
106 wakeup_32:
107 # Running in this code, but at low address; paging is not yet turned on.
108
109         movl    $__KERNEL_DS, %eax
110         movl    %eax, %ds
111
112         /*
113          * Prepare for entering 64bits mode
114          */
115
116         /* Enable PAE */
117         xorl    %eax, %eax
118         btsl    $5, %eax
119         movl    %eax, %cr4
120
121         /* Setup early boot stage 4 level pagetables */
122         leal    (wakeup_level4_pgt - wakeup_code)(%esi), %eax
123         movl    %eax, %cr3
124
125         /* Check if nx is implemented */
126         movl    $0x80000001, %eax
127         cpuid
128         movl    %edx,%edi
129
130         /* Enable Long Mode */
131         xorl    %eax, %eax
132         btsl    $_EFER_LME, %eax
133
134         /* No Execute supported? */
135         btl     $20,%edi
136         jnc     1f
137         btsl    $_EFER_NX, %eax
138                                 
139         /* Make changes effective */
140 1:      movl    $MSR_EFER, %ecx
141         xorl    %edx, %edx
142         wrmsr
143
144         xorl    %eax, %eax
145         btsl    $31, %eax                       /* Enable paging and in turn activate Long Mode */
146         btsl    $0, %eax                        /* Enable protected mode */
147
148         /* Make changes effective */
149         movl    %eax, %cr0
150
151         /* At this point:
152                 CR4.PAE must be 1
153                 CS.L must be 0
154                 CR3 must point to PML4
155                 Next instruction must be a branch
156                 This must be on identity-mapped page
157         */
158         /*
159          * At this point we're in long mode but in 32bit compatibility mode
160          * with EFER.LME = 1, CS.L = 0, CS.D = 1 (and in turn
161          * EFER.LMA = 1). Now we want to jump in 64bit mode, to do that we load
162          * the new gdt/idt that has __KERNEL_CS with CS.L = 1.
163          */
164
165         /* Finally jump in 64bit mode */
166         ljmp    *(wakeup_long64_vector - wakeup_code)(%esi)
167
168         .balign 4
169 wakeup_long64_vector:
170         .long   wakeup_long64 - wakeup_code
171         .word   __KERNEL_CS, 0
172
173 .code64
174
175         /* Hooray, we are in Long 64-bit mode (but still running in
176          * low memory)
177          */
178 wakeup_long64:
179         /*
180          * We must switch to a new descriptor in kernel space for the GDT
181          * because soon the kernel won't have access anymore to the userspace
182          * addresses where we're currently running on. We have to do that here
183          * because in 32bit we couldn't load a 64bit linear address.
184          */
185         lgdt    cpu_gdt_descr
186
187         movq    saved_magic, %rax
188         movq    $0x123456789abcdef0, %rdx
189         cmpq    %rdx, %rax
190         jne     bogus_64_magic
191
192         nop
193         nop
194         movw    $__KERNEL_DS, %ax
195         movw    %ax, %ss        
196         movw    %ax, %ds
197         movw    %ax, %es
198         movw    %ax, %fs
199         movw    %ax, %gs
200         movq    saved_rsp, %rsp
201
202         movq    saved_rbx, %rbx
203         movq    saved_rdi, %rdi
204         movq    saved_rsi, %rsi
205         movq    saved_rbp, %rbp
206
207         movq    saved_rip, %rax
208         jmp     *%rax
209
210 .code32
211
212         .align  64      
213 gdta:
214         /* Its good to keep gdt in sync with one in trampoline.S */
215         .word   0, 0, 0, 0                      # dummy
216         /* ??? Why I need the accessed bit set in order for this to work? */
217         .quad   0x00cf9b000000ffff              # __KERNEL32_CS
218         .quad   0x00af9b000000ffff              # __KERNEL_CS
219         .quad   0x00cf93000000ffff              # __KERNEL_DS
220
221 idt_48a:
222         .word   0                               # idt limit = 0
223         .word   0, 0                            # idt base = 0L
224
225 gdt_48a:
226         .word   0x800                           # gdt limit=2048,
227                                                 #  256 GDT entries
228         .long   gdta - wakeup_code              # gdt base (relocated in later)
229         
230 real_magic:     .quad 0
231 video_mode:     .quad 0
232 realmode_flags: .quad 0
233
234 .code16
235 bogus_real_magic:
236         jmp bogus_real_magic
237
238 .code64
239 bogus_64_magic:
240         jmp bogus_64_magic
241
242 /* This code uses an extended set of video mode numbers. These include:
243  * Aliases for standard modes
244  *      NORMAL_VGA (-1)
245  *      EXTENDED_VGA (-2)
246  *      ASK_VGA (-3)
247  * Video modes numbered by menu position -- NOT RECOMMENDED because of lack
248  * of compatibility when extending the table. These are between 0x00 and 0xff.
249  */
250 #define VIDEO_FIRST_MENU 0x0000
251
252 /* Standard BIOS video modes (BIOS number + 0x0100) */
253 #define VIDEO_FIRST_BIOS 0x0100
254
255 /* VESA BIOS video modes (VESA number + 0x0200) */
256 #define VIDEO_FIRST_VESA 0x0200
257
258 /* Video7 special modes (BIOS number + 0x0900) */
259 #define VIDEO_FIRST_V7 0x0900
260
261 # Setting of user mode (AX=mode ID) => CF=success
262
263 # For now, we only handle VESA modes (0x0200..0x03ff).  To handle other
264 # modes, we should probably compile in the video code from the boot
265 # directory.
266 .code16
267 mode_set:
268         movw    %ax, %bx
269         subb    $VIDEO_FIRST_VESA>>8, %bh
270         cmpb    $2, %bh
271         jb      check_vesa
272
273 setbad:
274         clc
275         ret
276
277 check_vesa:
278         orw     $0x4000, %bx                    # Use linear frame buffer
279         movw    $0x4f02, %ax                    # VESA BIOS mode set call
280         int     $0x10
281         cmpw    $0x004f, %ax                    # AL=4f if implemented
282         jnz     setbad                          # AH=0 if OK
283
284         stc
285         ret
286
287 wakeup_stack_begin:     # Stack grows down
288
289 .org    0xff0
290 wakeup_stack:           # Just below end of page
291
292 .org   0x1000
293 ENTRY(wakeup_level4_pgt)
294         .quad   level3_ident_pgt - __START_KERNEL_map + _KERNPG_TABLE
295         .fill   510,8,0
296         /* (2^48-(2*1024*1024*1024))/(2^39) = 511 */
297         .quad   level3_kernel_pgt - __START_KERNEL_map + _KERNPG_TABLE
298
299 ENTRY(wakeup_end)
300         
301 ##
302 # acpi_copy_wakeup_routine
303 #
304 # Copy the above routine to low memory.
305 #
306 # Parameters:
307 # %rdi: place to copy wakeup routine to
308 #
309 # Returned address is location of code in low memory (past data and stack)
310 #
311         .code64
312 ENTRY(acpi_copy_wakeup_routine)
313         pushq   %rax
314         pushq   %rdx
315
316         movl    saved_video_mode, %edx
317         movl    %edx, video_mode - wakeup_start (,%rdi)
318         movl    acpi_realmode_flags, %edx
319         movl    %edx, realmode_flags - wakeup_start (,%rdi)
320         movq    $0x12345678, real_magic - wakeup_start (,%rdi)
321         movq    $0x123456789abcdef0, %rdx
322         movq    %rdx, saved_magic
323
324         movq    saved_magic, %rax
325         movq    $0x123456789abcdef0, %rdx
326         cmpq    %rdx, %rax
327         jne     bogus_64_magic
328
329         # restore the regs we used
330         popq    %rdx
331         popq    %rax
332 ENTRY(do_suspend_lowlevel_s4bios)
333         ret
334
335         .align 2
336         .p2align 4,,15
337 .globl do_suspend_lowlevel
338         .type   do_suspend_lowlevel,@function
339 do_suspend_lowlevel:
340 .LFB5:
341         subq    $8, %rsp
342         xorl    %eax, %eax
343         call    save_processor_state
344
345         movq %rsp, saved_context_esp(%rip)
346         movq %rax, saved_context_eax(%rip)
347         movq %rbx, saved_context_ebx(%rip)
348         movq %rcx, saved_context_ecx(%rip)
349         movq %rdx, saved_context_edx(%rip)
350         movq %rbp, saved_context_ebp(%rip)
351         movq %rsi, saved_context_esi(%rip)
352         movq %rdi, saved_context_edi(%rip)
353         movq %r8,  saved_context_r08(%rip)
354         movq %r9,  saved_context_r09(%rip)
355         movq %r10, saved_context_r10(%rip)
356         movq %r11, saved_context_r11(%rip)
357         movq %r12, saved_context_r12(%rip)
358         movq %r13, saved_context_r13(%rip)
359         movq %r14, saved_context_r14(%rip)
360         movq %r15, saved_context_r15(%rip)
361         pushfq ; popq saved_context_eflags(%rip)
362
363         movq    $.L97, saved_rip(%rip)
364
365         movq %rsp,saved_rsp
366         movq %rbp,saved_rbp
367         movq %rbx,saved_rbx
368         movq %rdi,saved_rdi
369         movq %rsi,saved_rsi
370
371         addq    $8, %rsp
372         movl    $3, %edi
373         xorl    %eax, %eax
374         jmp     acpi_enter_sleep_state
375 .L97:
376         .p2align 4,,7
377 .L99:
378         .align 4
379         movl    $24, %eax
380         movw %ax, %ds
381         movq    saved_context+58(%rip), %rax
382         movq %rax, %cr4
383         movq    saved_context+50(%rip), %rax
384         movq %rax, %cr3
385         movq    saved_context+42(%rip), %rax
386         movq %rax, %cr2
387         movq    saved_context+34(%rip), %rax
388         movq %rax, %cr0
389         pushq saved_context_eflags(%rip) ; popfq
390         movq saved_context_esp(%rip), %rsp
391         movq saved_context_ebp(%rip), %rbp
392         movq saved_context_eax(%rip), %rax
393         movq saved_context_ebx(%rip), %rbx
394         movq saved_context_ecx(%rip), %rcx
395         movq saved_context_edx(%rip), %rdx
396         movq saved_context_esi(%rip), %rsi
397         movq saved_context_edi(%rip), %rdi
398         movq saved_context_r08(%rip), %r8
399         movq saved_context_r09(%rip), %r9
400         movq saved_context_r10(%rip), %r10
401         movq saved_context_r11(%rip), %r11
402         movq saved_context_r12(%rip), %r12
403         movq saved_context_r13(%rip), %r13
404         movq saved_context_r14(%rip), %r14
405         movq saved_context_r15(%rip), %r15
406
407         xorl    %eax, %eax
408         addq    $8, %rsp
409         jmp     restore_processor_state
410 .LFE5:
411 .Lfe5:
412         .size   do_suspend_lowlevel,.Lfe5-do_suspend_lowlevel
413         
414 .data
415 ALIGN
416 ENTRY(saved_rbp)        .quad   0
417 ENTRY(saved_rsi)        .quad   0
418 ENTRY(saved_rdi)        .quad   0
419 ENTRY(saved_rbx)        .quad   0
420
421 ENTRY(saved_rip)        .quad   0
422 ENTRY(saved_rsp)        .quad   0
423
424 ENTRY(saved_magic)      .quad   0