[PATCH] Minor 32bit compatibility fix for /dev/rtc
[linux-2.6/history.git] / arch / x86_64 / kernel / wakeup.S
blob8fe49f0375158cac0c667108d5c3d9f2ea4a3443
1 /*
2  * ACPI S3 entry/exit handling.
3  *              
4  * Notes:
5  * Relies on kernel being loaded below 4GB.
6  * Needs restore_low_mappings called before.
7  *                      
8  * Copyright 2003 by Andi Kleen, SuSE Labs.
9  *      
10  * Long mode entry loosely based on example code in chapter 14 of the x86-64 system 
11  * programmer's manual.
12  * 
13  * Notebook:    
15  FIXME need to interface with suspend.c properly. do_magic. check i386. rename to suspend64.S
16                 
17  Need to fix vgacon,mtrr,bluesmoke to do resume
18         
19  Interrupts should be off until the io-apic code has reinited the APIC.
20  Need support for that in the pm frame work or a special hack?
22  SMP support is non existent. Need to somehow restart the other CPUs again.
23  If CPU hotplug was working it could be used. Save/Restore needs to run on the same CPU.
25  Should check magic like i386 code
26         
27  suspend code copies something. check what it is.               
28  */
29         
30 #include <linux/linkage.h>
31         
32 #include <asm/msr.h>
33 #include <asm/segment.h>
34 #include <asm/page.h>
35                         
36 #define O(x) (x-acpi_wakeup)
37                 
38         .text
39         .code16
40 ENTRY(acpi_wakeup)
41         /* 16bit real mode entered from ACPI BIOS */
42         /* The machine is just through BIOS setup after power down and everything set up
43            by Linux needs to be restored. */
44         /* The code here needs to be position independent or manually relocated,
45            because it is copied to a <1MB page for real mode execution */
46         
47         /* A20 enabled (according to ACPI spec) */
48         /* cs = acpi_wakeup >> 4 ;  eip = acpi_wakeup & 0xF */
49                 
50         movw %cs,%ax
51         movw %ax,%ds    /* make %ds point to acpi_wakeup */
52         movw %ax,%ss
53         movw $O(wakeup_stack),%sp       /* setup stack */
55         pushl $0
56         popfl                   /* clear EFLAGS */
57         
58         lgdt %ds:O(pGDT)        /* load kernel GDT */
59         
60         movl $0x1,%eax          /* enable protected mode */
61         movl %eax,%cr0
63         movl %ds:O(wakeup_page_table),%edi
64         ljmpl  $__KERNEL16_CS,$0   /* -> s3_prot16 (filled in earlier by caller) */
65         
66         /* patched by s3_restore_state below */
67 pGDT:
68         .short 0
69         .quad  0
71         .align 4
72         .globl wakeup_page_table
73 wakeup_page_table:      
74         .long 0 
75         
76         .align 8
77 wakeup_stack:
78         .fill 128,1,0
79         .globl acpi_wakeup_end
80 acpi_wakeup_end:
81         /* end of real mode trampoline */
82                 
83         /* pointed to by __KERNEL16_CS:0 */     
84         .code16 
85 ENTRY(s3_prot16)
86         /* Now in 16bit protected mode, still no paging, stack/data segments invalid */
88         /* Prepare everything for 64bit paging, but still keep it turned off */
89         movl %cr4,%eax
90         bts  $5,%eax    /* set PAE bit */
91         movl %eax,%cr4
92         
93         movl %edi,%cr3  /* load kernel page table */
95         movl $0x80000001,%eax   
96         cpuid           /* no execute supported ? */
97         movl %edx,%esi  
98         
99         movl $MSR_EFER,%ecx
100         rdmsr 
101         bts $8,%eax     /* long mode */
102         bt  $20,%esi    /* NX supported ? */
103         jnc 1f
104         bt  $_EFER_NX,%eax
105 1:      
106         wrmsr           /* set temporary efer - real one is restored a bit later */
107         
108         movl %cr0,%eax
109         bts  $31,%eax   /* paging */
110         movl %eax,%cr0
112         /* running in identity mapping now */
114         /* go to 64bit code segment */
115         ljmpl $__KERNEL_CS,$s3_restore_state-__START_KERNEL_map
117         .code64                 
118         .macro  SAVEMSR msr,target
119         movl    $\msr,%ecx
120         rdmsr
121         shlq    $32,%rdx
122         orq     %rax,%rdx
123         movq    %rdx,\target(%rip)
124         .endm
126         .macro RESTMSR msr,src
127         movl    $\msr,%ecx
128         movq    \src(%rip),%rax
129         movq    %rax,%rdx
130         shrq    $32,%rdx
131         wrmsr
132         .endm
133         
134         .macro  SAVECTL reg
135         movq    %\reg,%rax
136         movq    %rax,saved_\reg(%rip)
137         .endm
138         
139         .macro  RESTCTL reg
140         movq    saved_\reg(%rip),%rax
141         movq    %rax,%\reg
142         .endm
144         /* Running in identity mapping, long mode */
145 s3_restore_state_low:
146         movq    $s3_restore_state,%rax
147         jmpq    *%rax   
149         /* Running in real kernel mapping now */
150 s3_restore_state:
151         xorl    %eax,%eax
152         movl    %eax,%ds
153         movq    saved_rsp(%rip),%rsp
154         movw    saved_ss(%rip),%ss
155         movw    saved_fs(%rip),%fs
156         movw    saved_gs(%rip),%gs
157         movw    saved_es(%rip),%es
158         movw    saved_ds(%rip),%ds
160         lidt    saved_idt
161         ltr     saved_tr
162         lldt    saved_ldt       
163         /* gdt is already loaded */
164         
165         RESTCTL cr0
166         RESTCTL cr4
167         /* cr3 is already loaded */     
168         
169         RESTMSR MSR_EFER,saved_efer
170         RESTMSR MSR_LSTAR,saved_lstar
171         RESTMSR MSR_CSTAR,saved_cstar
172         RESTMSR MSR_FS_BASE,saved_fs_base
173         RESTMSR MSR_GS_BASE,saved_gs_base
174         RESTMSR MSR_KERNEL_GS_BASE,saved_kernel_gs_base
175         RESTMSR MSR_SYSCALL_MASK,saved_syscall_mask
176                                 
177         fxrstor fpustate(%rip)
179         RESTCTL dr0
180         RESTCTL dr1
181         RESTCTL dr2
182         RESTCTL dr3
183         RESTCTL dr6
184         RESTCTL dr7
186         movq    saved_rflags(%rip),%rax
187         pushq   %rax
188         popfq
189                                                                 
190         movq    saved_rbp(%rip),%rbp
191         movq    saved_rbx(%rip),%rbx
192         movq    saved_r12(%rip),%r12
193         movq    saved_r13(%rip),%r13
194         movq    saved_r14(%rip),%r14
195         movq    saved_r15(%rip),%r15            
196         ret
197                 
198 ENTRY(acpi_prepare_wakeup)
199         sgdt    saved_gdt
200         
201         /* copy gdt descr and page table to low level wakeup code so that it can 
202            reload them early. */
203         movq    acpi_wakeup_address(%rip),%rax  
204         movw    saved_gdt+8(%rip),%cx
205         movw    %cx,O(pGDT)+8(%rax)     
206         movq    saved_gdt(%rip),%rcx
207         movq    %rcx,O(pGDT)(%rax)
208         
209         movq    %cr3,%rdi
210         movl    %edi,O(wakeup_page_table)(%rax)
211         ret
213         /* Save CPU state. */
214         /* Everything saved here needs to be restored above. */
215 ENTRY(do_suspend_lowlevel)
216         testl   %edi,%edi
217         jnz     s3_restore_state
218                 
219         SAVECTL cr0
220         SAVECTL cr4
221         SAVECTL cr3
222                 
223         str     saved_tr
224         sidt    saved_idt               
225         sgdt    saved_gdt
226         sldt    saved_ldt
227                         
228         SAVEMSR MSR_EFER,saved_efer
229         SAVEMSR MSR_LSTAR,saved_lstar
230         SAVEMSR MSR_CSTAR,saved_cstar
231         SAVEMSR MSR_FS_BASE,saved_fs_base
232         SAVEMSR MSR_GS_BASE,saved_gs_base
233         SAVEMSR MSR_KERNEL_GS_BASE,saved_kernel_gs_base
234         SAVEMSR MSR_SYSCALL_MASK,saved_syscall_mask
236         movw    %ds,saved_ds(%rip)
237         movw    %es,saved_es(%rip)
238         movw    %fs,saved_fs(%rip)
239         movw    %gs,saved_gs(%rip)
240         movw    %ss,saved_ss(%rip)
241         movq    %rsp,saved_rsp(%rip)
242         
243         pushfq
244         popq    %rax
245         movq    %rax,saved_rflags(%rip)
247         SAVECTL  dr0
248         SAVECTL  dr1
249         SAVECTL  dr2
250         SAVECTL  dr3
251         SAVECTL  dr6
252         SAVECTL  dr7
253         
254         fxsave  fpustate(%rip) 
255         
256         /* finally save callee saved registers */
257         movq    %rbp,saved_rbp(%rip)
258         movq    %rbx,saved_rbx(%rip)
259         movq    %r12,saved_r12(%rip)
260         movq    %r13,saved_r13(%rip)
261         movq    %r14,saved_r14(%rip)
262         movq    %r15,saved_r15(%rip)
263         movq    $3,%rdi         
264         call    acpi_enter_sleep_state
265         ret     /* should not happen */
267         .data
268         .align 8
269 saved_efer:     .quad 0
270 saved_lstar:    .quad 0
271 saved_cstar:    .quad 0
272 saved_cr4:      .quad 0
273 saved_cr3:      .quad 0
274 saved_cr0:      .quad 0 
275 saved_rbp:      .quad 0
276 saved_rbx:      .quad 0
277 saved_rsp:      .quad 0
278 saved_r12:      .quad 0
279 saved_r13:      .quad 0
280 saved_r14:      .quad 0
281 saved_r15:      .quad 0
282 saved_rflags:   .quad 0
283 saved_gs_base:  .quad 0
284 saved_fs_base:  .quad 0
285 saved_kernel_gs_base:   .quad 0
286 saved_syscall_mask:     .quad 0
287 saved_dr0:      .quad 0 
288 saved_dr1:      .quad 0 
289 saved_dr2:      .quad 0 
290 saved_dr3:      .quad 0 
291 saved_dr6:      .quad 0 
292 saved_dr7:      .quad 0 
293 saved_ds:       .short 0
294 saved_fs:       .short 0
295 saved_gs:       .short 0
296 saved_es:       .short 0
297 saved_ss:       .short 0        
298 saved_idt:      .short 0
299                 .quad 0
300 saved_ldt:      .short 0
301 saved_gdt:      .short 0
302                 .quad 0         
303 saved_tr:       .short 0
304                         
305                 .align 16
306 fpustate:       .fill  512,1,0