[PATCH] x86-64: Get rid of dead code in suspend resume
[cascardo/linux.git] / arch / x86_64 / kernel / acpi / wakeup.S
1 .text
2 #include <linux/linkage.h>
3 #include <asm/segment.h>
4 #include <asm/page.h>
5 #include <asm/msr.h>
6
7 # Copyright 2003 Pavel Machek <pavel@suse.cz>, distribute under GPLv2
8 #
9 # wakeup_code runs in real mode, and at unknown address (determined at run-time).
10 # Therefore it must only use relative jumps/calls. 
11 #
12 # Do we need to deal with A20? It is okay: ACPI specs says A20 must be enabled
13 #
14 # If physical address of wakeup_code is 0x12345, BIOS should call us with
15 # cs = 0x1234, eip = 0x05
16 #
17
18
19 ALIGN
20         .align  16
21 ENTRY(wakeup_start)
22 wakeup_code:
23         wakeup_code_start = .
24         .code16
25
26 # Running in *copy* of this code, somewhere in low 1MB.
27
28         movb    $0xa1, %al      ;  outb %al, $0x80
29         cli
30         cld
31         # setup data segment
32         movw    %cs, %ax
33         movw    %ax, %ds                                        # Make ds:0 point to wakeup_start
34         movw    %ax, %ss
35         mov     $(wakeup_stack - wakeup_code), %sp              # Private stack is needed for ASUS board
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_seta
56 1:
57
58         movw    $0xb800, %ax
59         movw    %ax,%fs
60         movw    $0x0e00 + 'L', %fs:(0x10)
61
62         movb    $0xa2, %al      ;  outb %al, $0x80
63         
64         lidt    %ds:idt_48a - wakeup_code
65         xorl    %eax, %eax
66         movw    %ds, %ax                        # (Convert %ds:gdt to a linear ptr)
67         shll    $4, %eax
68         addl    $(gdta - wakeup_code), %eax
69         movl    %eax, gdt_48a +2 - wakeup_code
70         lgdtl   %ds:gdt_48a - wakeup_code       # load gdt with whatever is
71                                                 # appropriate
72
73         movl    $1, %eax                        # protected mode (PE) bit
74         lmsw    %ax                             # This is it!
75         jmp     1f
76 1:
77
78         .byte 0x66, 0xea                        # prefix + jmpi-opcode
79         .long   wakeup_32 - __START_KERNEL_map
80         .word   __KERNEL_CS
81
82         .code32
83 wakeup_32:
84 # Running in this code, but at low address; paging is not yet turned on.
85         movb    $0xa5, %al      ;  outb %al, $0x80
86
87         /* Check if extended functions are implemented */               
88         movl    $0x80000000, %eax
89         cpuid
90         cmpl    $0x80000000, %eax
91         jbe     bogus_cpu
92         wbinvd
93         mov     $0x80000001, %eax
94         cpuid
95         btl     $29, %edx
96         jnc     bogus_cpu
97         movl    %edx,%edi
98         
99         movw    $__KERNEL_DS, %ax
100         movw    %ax, %ds
101         movw    %ax, %es
102         movw    %ax, %fs
103         movw    %ax, %gs
104
105         movw    $__KERNEL_DS, %ax       
106         movw    %ax, %ss
107
108         mov     $(wakeup_stack - __START_KERNEL_map), %esp
109         movl    saved_magic - __START_KERNEL_map, %eax
110         cmpl    $0x9abcdef0, %eax
111         jne     bogus_32_magic
112
113         /*
114          * Prepare for entering 64bits mode
115          */
116
117         /* Enable PAE mode and PGE */
118         xorl    %eax, %eax
119         btsl    $5, %eax
120         btsl    $7, %eax
121         movl    %eax, %cr4
122
123         /* Setup early boot stage 4 level pagetables */
124         movl    $(wakeup_level4_pgt - __START_KERNEL_map), %eax
125         movl    %eax, %cr3
126
127         /* Setup EFER (Extended Feature Enable Register) */
128         movl    $MSR_EFER, %ecx
129         rdmsr
130         /* Fool rdmsr and reset %eax to avoid dependences */
131         xorl    %eax, %eax
132         /* Enable Long Mode */
133         btsl    $_EFER_LME, %eax
134         /* Enable System Call */
135         btsl    $_EFER_SCE, %eax
136
137         /* No Execute supported? */     
138         btl     $20,%edi
139         jnc     1f
140         btsl    $_EFER_NX, %eax
141 1:      
142                                 
143         /* Make changes effective */
144         wrmsr
145         wbinvd
146
147         xorl    %eax, %eax
148         btsl    $31, %eax                       /* Enable paging and in turn activate Long Mode */
149         btsl    $0, %eax                        /* Enable protected mode */
150         btsl    $1, %eax                        /* Enable MP */
151         btsl    $4, %eax                        /* Enable ET */
152         btsl    $5, %eax                        /* Enable NE */
153         btsl    $16, %eax                       /* Enable WP */
154         btsl    $18, %eax                       /* Enable AM */
155
156         /* Make changes effective */
157         movl    %eax, %cr0
158         /* At this point:
159                 CR4.PAE must be 1
160                 CS.L must be 0
161                 CR3 must point to PML4
162                 Next instruction must be a branch
163                 This must be on identity-mapped page
164         */
165         jmp     reach_compatibility_mode
166 reach_compatibility_mode:
167         movw    $0x0e00 + 'i', %ds:(0xb8012)
168         movb    $0xa8, %al      ;  outb %al, $0x80;     
169                 
170         /*
171          * At this point we're in long mode but in 32bit compatibility mode
172          * with EFER.LME = 1, CS.L = 0, CS.D = 1 (and in turn
173          * EFER.LMA = 1). Now we want to jump in 64bit mode, to do that we load
174          * the new gdt/idt that has __KERNEL_CS with CS.L = 1.
175          */
176
177         movw    $0x0e00 + 'n', %ds:(0xb8014)
178         movb    $0xa9, %al      ;  outb %al, $0x80
179         
180         /* Load new GDT with the 64bit segment using 32bit descriptor */
181         movl    $(pGDT32 - __START_KERNEL_map), %eax
182         lgdt    (%eax)
183
184         movl    $(wakeup_jumpvector - __START_KERNEL_map), %eax
185         /* Finally jump in 64bit mode */
186         ljmp    *(%eax)
187
188 wakeup_jumpvector:
189         .long   wakeup_long64 - __START_KERNEL_map
190         .word   __KERNEL_CS
191
192 .code64
193
194         /*      Hooray, we are in Long 64-bit mode (but still running in low memory) */
195 wakeup_long64:
196         /*
197          * We must switch to a new descriptor in kernel space for the GDT
198          * because soon the kernel won't have access anymore to the userspace
199          * addresses where we're currently running on. We have to do that here
200          * because in 32bit we couldn't load a 64bit linear address.
201          */
202         lgdt    cpu_gdt_descr - __START_KERNEL_map
203
204         movw    $0x0e00 + 'u', %ds:(0xb8016)
205         
206         nop
207         nop
208         movw    $__KERNEL_DS, %ax
209         movw    %ax, %ss        
210         movw    %ax, %ds
211         movw    %ax, %es
212         movw    %ax, %fs
213         movw    %ax, %gs
214         movq    saved_esp, %rsp
215
216         movw    $0x0e00 + 'x', %ds:(0xb8018)
217         movq    saved_ebx, %rbx
218         movq    saved_edi, %rdi
219         movq    saved_esi, %rsi
220         movq    saved_ebp, %rbp
221
222         movw    $0x0e00 + '!', %ds:(0xb801a)
223         movq    saved_eip, %rax
224         jmp     *%rax
225
226 .code32
227
228         .align  64      
229 gdta:
230         .word   0, 0, 0, 0                      # dummy
231
232         .word   0, 0, 0, 0                      # unused
233
234         .word   0xFFFF                          # 4Gb - (0x100000*0x1000 = 4Gb)
235         .word   0                               # base address = 0
236         .word   0x9B00                          # code read/exec. ??? Why I need 0x9B00 (as opposed to 0x9A00 in order for this to work?)
237         .word   0x00CF                          # granularity = 4096, 386
238                                                 #  (+5th nibble of limit)
239
240         .word   0xFFFF                          # 4Gb - (0x100000*0x1000 = 4Gb)
241         .word   0                               # base address = 0
242         .word   0x9200                          # data read/write
243         .word   0x00CF                          # granularity = 4096, 386
244                                                 #  (+5th nibble of limit)
245 # this is 64bit descriptor for code
246         .word   0xFFFF
247         .word   0
248         .word   0x9A00                          # code read/exec
249         .word   0x00AF                          # as above, but it is long mode and with D=0
250
251 idt_48a:
252         .word   0                               # idt limit = 0
253         .word   0, 0                            # idt base = 0L
254
255 gdt_48a:
256         .word   0x8000                          # gdt limit=2048,
257                                                 #  256 GDT entries
258         .word   0, 0                            # gdt base (filled in later)
259         
260         
261 real_magic:     .quad 0
262 video_mode:     .quad 0
263 video_flags:    .quad 0
264
265 bogus_real_magic:
266         movb    $0xba,%al       ;  outb %al,$0x80               
267         jmp bogus_real_magic
268
269 bogus_32_magic:
270         movb    $0xb3,%al       ;  outb %al,$0x80
271         jmp bogus_32_magic
272
273 bogus_cpu:
274         movb    $0xbc,%al       ;  outb %al,$0x80
275         jmp bogus_cpu
276
277         
278 /* This code uses an extended set of video mode numbers. These include:
279  * Aliases for standard modes
280  *      NORMAL_VGA (-1)
281  *      EXTENDED_VGA (-2)
282  *      ASK_VGA (-3)
283  * Video modes numbered by menu position -- NOT RECOMMENDED because of lack
284  * of compatibility when extending the table. These are between 0x00 and 0xff.
285  */
286 #define VIDEO_FIRST_MENU 0x0000
287
288 /* Standard BIOS video modes (BIOS number + 0x0100) */
289 #define VIDEO_FIRST_BIOS 0x0100
290
291 /* VESA BIOS video modes (VESA number + 0x0200) */
292 #define VIDEO_FIRST_VESA 0x0200
293
294 /* Video7 special modes (BIOS number + 0x0900) */
295 #define VIDEO_FIRST_V7 0x0900
296
297 # Setting of user mode (AX=mode ID) => CF=success
298 mode_seta:
299         movw    %ax, %bx
300 #if 0
301         cmpb    $0xff, %ah
302         jz      setalias
303
304         testb   $VIDEO_RECALC>>8, %ah
305         jnz     _setrec
306
307         cmpb    $VIDEO_FIRST_RESOLUTION>>8, %ah
308         jnc     setres
309         
310         cmpb    $VIDEO_FIRST_SPECIAL>>8, %ah
311         jz      setspc
312
313         cmpb    $VIDEO_FIRST_V7>>8, %ah
314         jz      setv7
315 #endif
316         
317         cmpb    $VIDEO_FIRST_VESA>>8, %ah
318         jnc     check_vesaa
319 #if 0   
320         orb     %ah, %ah
321         jz      setmenu
322 #endif
323         
324         decb    %ah
325 #       jz      setbios                           Add bios modes later
326
327 setbada:        clc
328         ret
329
330 check_vesaa:
331         subb    $VIDEO_FIRST_VESA>>8, %bh
332         orw     $0x4000, %bx                    # Use linear frame buffer
333         movw    $0x4f02, %ax                    # VESA BIOS mode set call
334         int     $0x10
335         cmpw    $0x004f, %ax                    # AL=4f if implemented
336         jnz     _setbada                                # AH=0 if OK
337
338         stc
339         ret
340
341 _setbada: jmp setbada
342
343 wakeup_stack_begin:     # Stack grows down
344
345 .org    0xff0
346 wakeup_stack:           # Just below end of page
347
348 ENTRY(wakeup_end)
349         
350 ##
351 # acpi_copy_wakeup_routine
352 #
353 # Copy the above routine to low memory.
354 #
355 # Parameters:
356 # %rdi: place to copy wakeup routine to
357 #
358 # Returned address is location of code in low memory (past data and stack)
359 #
360         .code64
361 ENTRY(acpi_copy_wakeup_routine)
362         pushq   %rax
363         pushq   %rdx
364
365         movl    saved_video_mode, %edx
366         movl    %edx, video_mode - wakeup_start (,%rdi)
367         movl    acpi_video_flags, %edx
368         movl    %edx, video_flags - wakeup_start (,%rdi)
369         movq    $0x12345678, real_magic - wakeup_start (,%rdi)
370         movq    $0x123456789abcdef0, %rdx
371         movq    %rdx, saved_magic
372
373         movl    saved_magic - __START_KERNEL_map, %eax
374         cmpl    $0x9abcdef0, %eax
375         jne     bogus_32_magic
376
377         # restore the regs we used
378         popq    %rdx
379         popq    %rax
380 ENTRY(do_suspend_lowlevel_s4bios)
381         ret
382
383         .align 2
384         .p2align 4,,15
385 .globl do_suspend_lowlevel
386         .type   do_suspend_lowlevel,@function
387 do_suspend_lowlevel:
388 .LFB5:
389         subq    $8, %rsp
390         xorl    %eax, %eax
391         call    save_processor_state
392
393         movq %rsp, saved_context_esp(%rip)
394         movq %rax, saved_context_eax(%rip)
395         movq %rbx, saved_context_ebx(%rip)
396         movq %rcx, saved_context_ecx(%rip)
397         movq %rdx, saved_context_edx(%rip)
398         movq %rbp, saved_context_ebp(%rip)
399         movq %rsi, saved_context_esi(%rip)
400         movq %rdi, saved_context_edi(%rip)
401         movq %r8,  saved_context_r08(%rip)
402         movq %r9,  saved_context_r09(%rip)
403         movq %r10, saved_context_r10(%rip)
404         movq %r11, saved_context_r11(%rip)
405         movq %r12, saved_context_r12(%rip)
406         movq %r13, saved_context_r13(%rip)
407         movq %r14, saved_context_r14(%rip)
408         movq %r15, saved_context_r15(%rip)
409         pushfq ; popq saved_context_eflags(%rip)
410
411         movq    $.L97, saved_eip(%rip)
412
413         movq %rsp,saved_esp
414         movq %rbp,saved_ebp
415         movq %rbx,saved_ebx
416         movq %rdi,saved_edi
417         movq %rsi,saved_esi
418
419         addq    $8, %rsp
420         movl    $3, %edi
421         xorl    %eax, %eax
422         jmp     acpi_enter_sleep_state
423 .L97:
424         .p2align 4,,7
425 .L99:
426         .align 4
427         movl    $24, %eax
428         movw %ax, %ds
429         movq    saved_context+58(%rip), %rax
430         movq %rax, %cr4
431         movq    saved_context+50(%rip), %rax
432         movq %rax, %cr3
433         movq    saved_context+42(%rip), %rax
434         movq %rax, %cr2
435         movq    saved_context+34(%rip), %rax
436         movq %rax, %cr0
437         pushq saved_context_eflags(%rip) ; popfq
438         movq saved_context_esp(%rip), %rsp
439         movq saved_context_ebp(%rip), %rbp
440         movq saved_context_eax(%rip), %rax
441         movq saved_context_ebx(%rip), %rbx
442         movq saved_context_ecx(%rip), %rcx
443         movq saved_context_edx(%rip), %rdx
444         movq saved_context_esi(%rip), %rsi
445         movq saved_context_edi(%rip), %rdi
446         movq saved_context_r08(%rip), %r8
447         movq saved_context_r09(%rip), %r9
448         movq saved_context_r10(%rip), %r10
449         movq saved_context_r11(%rip), %r11
450         movq saved_context_r12(%rip), %r12
451         movq saved_context_r13(%rip), %r13
452         movq saved_context_r14(%rip), %r14
453         movq saved_context_r15(%rip), %r15
454
455         xorl    %eax, %eax
456         addq    $8, %rsp
457         jmp     restore_processor_state
458 .LFE5:
459 .Lfe5:
460         .size   do_suspend_lowlevel,.Lfe5-do_suspend_lowlevel
461         
462 .data
463 ALIGN
464 ENTRY(saved_ebp)        .quad   0
465 ENTRY(saved_esi)        .quad   0
466 ENTRY(saved_edi)        .quad   0
467 ENTRY(saved_ebx)        .quad   0
468
469 ENTRY(saved_eip)        .quad   0
470 ENTRY(saved_esp)        .quad   0
471
472 ENTRY(saved_magic)      .quad   0