2 * ACPI S3 entry/exit handling.
5 * Relies on kernel being loaded below 4GB.
6 * Needs restore_low_mappings called before.
8 * Copyright 2003 by Andi Kleen, SuSE Labs.
10 * Long mode entry loosely based on example code in chapter 14 of the x86-64 system
11 * programmer's manual.
15 FIXME need to interface with suspend.c properly. do_magic. check i386. rename to suspend64.S
17 Need to fix vgacon,mtrr,bluesmoke to do resume
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
27 suspend code copies something. check what it is.
30 #include <linux/linkage.h>
33 #include <asm/segment.h>
36 #define O(x) (x-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 */
47 /* A20 enabled (according to ACPI spec) */
48 /* cs = acpi_wakeup >> 4 ; eip = acpi_wakeup & 0xF */
51 movw %ax,%ds /* make %ds point to acpi_wakeup */
53 movw $O(wakeup_stack),%sp /* setup stack */
56 popfl /* clear EFLAGS */
58 lgdt %ds:O(pGDT) /* load kernel GDT */
60 movl $0x1,%eax /* enable protected mode */
63 movl %ds:O(wakeup_page_table),%edi
64 ljmpl $__KERNEL16_CS,$0 /* -> s3_prot16 (filled in earlier by caller) */
66 /* patched by s3_restore_state below */
72 .globl wakeup_page_table
79 .globl acpi_wakeup_end
81 /* end of real mode trampoline */
83 /* pointed to by __KERNEL16_CS:0 */
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 */
90 bts $5,%eax /* set PAE bit */
93 movl %edi,%cr3 /* load kernel page table */
96 cpuid /* no execute supported ? */
101 bts $8,%eax /* long mode */
102 bt $20,%esi /* NX supported ? */
106 wrmsr /* set temporary efer - real one is restored a bit later */
109 bts $31,%eax /* paging */
112 /* running in identity mapping now */
114 /* go to 64bit code segment */
115 ljmpl $__KERNEL_CS,$s3_restore_state-__START_KERNEL_map
118 .macro SAVEMSR msr,target
123 movq %rdx,\target(%rip)
126 .macro RESTMSR msr,src
136 movq %rax,saved_\reg(%rip)
140 movq saved_\reg(%rip),%rax
144 /* Running in identity mapping, long mode */
145 s3_restore_state_low:
146 movq $s3_restore_state,%rax
149 /* Running in real kernel mapping now */
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
163 /* gdt is already loaded */
167 /* cr3 is already loaded */
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
177 fxrstor fpustate(%rip)
186 movq saved_rflags(%rip),%rax
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
198 ENTRY(acpi_prepare_wakeup)
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)
210 movl %edi,O(wakeup_page_table)(%rax)
213 /* Save CPU state. */
214 /* Everything saved here needs to be restored above. */
215 ENTRY(do_suspend_lowlevel)
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)
245 movq %rax,saved_rflags(%rip)
254 fxsave fpustate(%rip)
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)
264 call acpi_enter_sleep_state
265 ret /* should not happen */
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
306 fpustate: .fill 512,1,0