x86: unify power/cpu_(32|64) regarding restoring processor state
[sfrench/cifs-2.6.git] / arch / x86 / power / cpu_32.c
1 /*
2  * Suspend support specific for i386.
3  *
4  * Distribute under GPLv2
5  *
6  * Copyright (c) 2002 Pavel Machek <pavel@suse.cz>
7  * Copyright (c) 2001 Patrick Mochel <mochel@osdl.org>
8  */
9
10 #include <linux/suspend.h>
11 #include <linux/smp.h>
12
13 #include <asm/pgtable.h>
14 #include <asm/proto.h>
15 #include <asm/mtrr.h>
16 #include <asm/page.h>
17 #include <asm/mce.h>
18 #include <asm/xcr.h>
19 #include <asm/suspend.h>
20
21 #ifdef CONFIG_X86_32
22 static struct saved_context saved_context;
23
24 unsigned long saved_context_ebx;
25 unsigned long saved_context_esp, saved_context_ebp;
26 unsigned long saved_context_esi, saved_context_edi;
27 unsigned long saved_context_eflags;
28 #else
29 /* CONFIG_X86_64 */
30 struct saved_context saved_context;
31 #endif
32
33 /**
34  *      __save_processor_state - save CPU registers before creating a
35  *              hibernation image and before restoring the memory state from it
36  *      @ctxt - structure to store the registers contents in
37  *
38  *      NOTE: If there is a CPU register the modification of which by the
39  *      boot kernel (ie. the kernel used for loading the hibernation image)
40  *      might affect the operations of the restored target kernel (ie. the one
41  *      saved in the hibernation image), then its contents must be saved by this
42  *      function.  In other words, if kernel A is hibernated and different
43  *      kernel B is used for loading the hibernation image into memory, the
44  *      kernel A's __save_processor_state() function must save all registers
45  *      needed by kernel A, so that it can operate correctly after the resume
46  *      regardless of what kernel B does in the meantime.
47  */
48 static void __save_processor_state(struct saved_context *ctxt)
49 {
50 #ifdef CONFIG_X86_32
51         mtrr_save_fixed_ranges(NULL);
52 #endif
53         kernel_fpu_begin();
54
55         /*
56          * descriptor tables
57          */
58 #ifdef CONFIG_X86_32
59         store_gdt(&ctxt->gdt);
60         store_idt(&ctxt->idt);
61 #else
62 /* CONFIG_X86_64 */
63         store_gdt((struct desc_ptr *)&ctxt->gdt_limit);
64         store_idt((struct desc_ptr *)&ctxt->idt_limit);
65 #endif
66         store_tr(ctxt->tr);
67
68         /* XMM0..XMM15 should be handled by kernel_fpu_begin(). */
69         /*
70          * segment registers
71          */
72 #ifdef CONFIG_X86_32
73         savesegment(es, ctxt->es);
74         savesegment(fs, ctxt->fs);
75         savesegment(gs, ctxt->gs);
76         savesegment(ss, ctxt->ss);
77 #else
78 /* CONFIG_X86_64 */
79         asm volatile ("movw %%ds, %0" : "=m" (ctxt->ds));
80         asm volatile ("movw %%es, %0" : "=m" (ctxt->es));
81         asm volatile ("movw %%fs, %0" : "=m" (ctxt->fs));
82         asm volatile ("movw %%gs, %0" : "=m" (ctxt->gs));
83         asm volatile ("movw %%ss, %0" : "=m" (ctxt->ss));
84
85         rdmsrl(MSR_FS_BASE, ctxt->fs_base);
86         rdmsrl(MSR_GS_BASE, ctxt->gs_base);
87         rdmsrl(MSR_KERNEL_GS_BASE, ctxt->gs_kernel_base);
88         mtrr_save_fixed_ranges(NULL);
89
90         rdmsrl(MSR_EFER, ctxt->efer);
91 #endif
92
93         /*
94          * control registers
95          */
96         ctxt->cr0 = read_cr0();
97         ctxt->cr2 = read_cr2();
98         ctxt->cr3 = read_cr3();
99 #ifdef CONFIG_X86_32
100         ctxt->cr4 = read_cr4_safe();
101 #else
102 /* CONFIG_X86_64 */
103         ctxt->cr4 = read_cr4();
104         ctxt->cr8 = read_cr8();
105 #endif
106 }
107
108 /* Needed by apm.c */
109 void save_processor_state(void)
110 {
111         __save_processor_state(&saved_context);
112 }
113 #ifdef CONFIG_X86_32
114 EXPORT_SYMBOL(save_processor_state);
115 #endif
116
117 static void do_fpu_end(void)
118 {
119         /*
120          * Restore FPU regs if necessary.
121          */
122         kernel_fpu_end();
123 }
124
125 static void fix_processor_context(void)
126 {
127         int cpu = smp_processor_id();
128         struct tss_struct *t = &per_cpu(init_tss, cpu);
129
130         set_tss_desc(cpu, t);   /*
131                                  * This just modifies memory; should not be
132                                  * necessary. But... This is necessary, because
133                                  * 386 hardware has concept of busy TSS or some
134                                  * similar stupidity.
135                                  */
136
137 #ifdef CONFIG_X86_64
138         get_cpu_gdt_table(cpu)[GDT_ENTRY_TSS].type = 9;
139
140         syscall_init();                         /* This sets MSR_*STAR and related */
141 #endif
142         load_TR_desc();                         /* This does ltr */
143         load_LDT(&current->active_mm->context); /* This does lldt */
144
145         /*
146          * Now maybe reload the debug registers
147          */
148         if (current->thread.debugreg7) {
149 #ifdef CONFIG_X86_32
150                 set_debugreg(current->thread.debugreg0, 0);
151                 set_debugreg(current->thread.debugreg1, 1);
152                 set_debugreg(current->thread.debugreg2, 2);
153                 set_debugreg(current->thread.debugreg3, 3);
154                 /* no 4 and 5 */
155                 set_debugreg(current->thread.debugreg6, 6);
156                 set_debugreg(current->thread.debugreg7, 7);
157 #else
158                 /* CONFIG_X86_64 */
159                 loaddebug(&current->thread, 0);
160                 loaddebug(&current->thread, 1);
161                 loaddebug(&current->thread, 2);
162                 loaddebug(&current->thread, 3);
163                 /* no 4 and 5 */
164                 loaddebug(&current->thread, 6);
165                 loaddebug(&current->thread, 7);
166 #endif
167         }
168
169 }
170
171 /**
172  *      __restore_processor_state - restore the contents of CPU registers saved
173  *              by __save_processor_state()
174  *      @ctxt - structure to load the registers contents from
175  */
176 static void __restore_processor_state(struct saved_context *ctxt)
177 {
178         /*
179          * control registers
180          */
181         /* cr4 was introduced in the Pentium CPU */
182 #ifdef CONFIG_X86_32
183         if (ctxt->cr4)
184                 write_cr4(ctxt->cr4);
185 #else
186 /* CONFIG X86_64 */
187         wrmsrl(MSR_EFER, ctxt->efer);
188         write_cr8(ctxt->cr8);
189         write_cr4(ctxt->cr4);
190 #endif
191         write_cr3(ctxt->cr3);
192         write_cr2(ctxt->cr2);
193         write_cr0(ctxt->cr0);
194
195         /*
196          * now restore the descriptor tables to their proper values
197          * ltr is done i fix_processor_context().
198          */
199 #ifdef CONFIG_X86_32
200         load_gdt(&ctxt->gdt);
201         load_idt(&ctxt->idt);
202 #else
203 /* CONFIG_X86_64 */
204         load_gdt((const struct desc_ptr *)&ctxt->gdt_limit);
205         load_idt((const struct desc_ptr *)&ctxt->idt_limit);
206 #endif
207
208         /*
209          * segment registers
210          */
211 #ifdef CONFIG_X86_32
212         loadsegment(es, ctxt->es);
213         loadsegment(fs, ctxt->fs);
214         loadsegment(gs, ctxt->gs);
215         loadsegment(ss, ctxt->ss);
216
217         /*
218          * sysenter MSRs
219          */
220         if (boot_cpu_has(X86_FEATURE_SEP))
221                 enable_sep_cpu();
222 #else
223 /* CONFIG_X86_64 */
224         asm volatile ("movw %0, %%ds" :: "r" (ctxt->ds));
225         asm volatile ("movw %0, %%es" :: "r" (ctxt->es));
226         asm volatile ("movw %0, %%fs" :: "r" (ctxt->fs));
227         load_gs_index(ctxt->gs);
228         asm volatile ("movw %0, %%ss" :: "r" (ctxt->ss));
229
230         wrmsrl(MSR_FS_BASE, ctxt->fs_base);
231         wrmsrl(MSR_GS_BASE, ctxt->gs_base);
232         wrmsrl(MSR_KERNEL_GS_BASE, ctxt->gs_kernel_base);
233 #endif
234
235         /*
236          * restore XCR0 for xsave capable cpu's.
237          */
238         if (cpu_has_xsave)
239                 xsetbv(XCR_XFEATURE_ENABLED_MASK, pcntxt_mask);
240
241         fix_processor_context();
242
243         do_fpu_end();
244         mtrr_ap_init();
245
246 #ifdef CONFIG_X86_32
247         mcheck_init(&boot_cpu_data);
248 #endif
249 }
250
251 /* Needed by apm.c */
252 void restore_processor_state(void)
253 {
254         __restore_processor_state(&saved_context);
255 }
256 #ifdef CONFIG_X86_32
257 EXPORT_SYMBOL(restore_processor_state);
258 #endif