1#ifndef _ASM_X86_SYSTEM_H
2#define _ASM_X86_SYSTEM_H
3
4#include <asm/asm.h>
5#include <asm/segment.h>
6#include <asm/cpufeature.h>
7#include <asm/cmpxchg.h>
8#include <asm/nops.h>
9
10#include <linux/kernel.h>
11#include <linux/irqflags.h>
12
13
14#ifdef CONFIG_IA32_EMULATION
15# define AT_VECTOR_SIZE_ARCH 2
16#else
17# define AT_VECTOR_SIZE_ARCH 1
18#endif
19
20#ifdef CONFIG_X86_32
21
22struct task_struct;
23struct task_struct *__switch_to(struct task_struct *prev,
24 struct task_struct *next);
25
26
27
28
29
30#define switch_to(prev, next, last) \
31do { \
32
33
34
35
36
37
38 \
39 unsigned long ebx, ecx, edx, esi, edi; \
40 \
41 asm volatile("pushfl\n\t" \
42 "pushl %%ebp\n\t" \
43 "movl %%esp,%[prev_sp]\n\t" \
44 "movl %[next_sp],%%esp\n\t" \
45 "movl $1f,%[prev_ip]\n\t" \
46 "pushl %[next_ip]\n\t" \
47 "jmp __switch_to\n" \
48 "1:\t" \
49 "popl %%ebp\n\t" \
50 "popfl\n" \
51 \
52 \
53 : [prev_sp] "=m" (prev->thread.sp), \
54 [prev_ip] "=m" (prev->thread.ip), \
55 "=a" (last), \
56 \
57 \
58 "=b" (ebx), "=c" (ecx), "=d" (edx), \
59 "=S" (esi), "=D" (edi) \
60 \
61 \
62 : [next_sp] "m" (next->thread.sp), \
63 [next_ip] "m" (next->thread.ip), \
64 \
65 \
66 [prev] "a" (prev), \
67 [next] "d" (next) \
68 \
69 : \
70 "memory"); \
71} while (0)
72
73
74
75
76#define HAVE_DISABLE_HLT
77#else
78#define __SAVE(reg, offset) "movq %%" #reg ",(14-" #offset ")*8(%%rsp)\n\t"
79#define __RESTORE(reg, offset) "movq (14-" #offset ")*8(%%rsp),%%" #reg "\n\t"
80
81
82#define SAVE_CONTEXT "pushf ; pushq %%rbp ; movq %%rsi,%%rbp\n\t"
83#define RESTORE_CONTEXT "movq %%rbp,%%rsi ; popq %%rbp ; popf\t"
84
85#define __EXTRA_CLOBBER \
86 , "rcx", "rbx", "rdx", "r8", "r9", "r10", "r11", \
87 "r12", "r13", "r14", "r15"
88
89
90#define switch_to(prev, next, last) \
91 asm volatile(SAVE_CONTEXT \
92 "movq %%rsp,%P[threadrsp](%[prev])\n\t" \
93 "movq %P[threadrsp](%[next]),%%rsp\n\t" \
94 "call __switch_to\n\t" \
95 ".globl thread_return\n" \
96 "thread_return:\n\t" \
97 "movq %%gs:%P[pda_pcurrent],%%rsi\n\t" \
98 "movq %P[thread_info](%%rsi),%%r8\n\t" \
99 LOCK_PREFIX "btr %[tif_fork],%P[ti_flags](%%r8)\n\t" \
100 "movq %%rax,%%rdi\n\t" \
101 "jc ret_from_fork\n\t" \
102 RESTORE_CONTEXT \
103 : "=a" (last) \
104 : [next] "S" (next), [prev] "D" (prev), \
105 [threadrsp] "i" (offsetof(struct task_struct, thread.sp)), \
106 [ti_flags] "i" (offsetof(struct thread_info, flags)), \
107 [tif_fork] "i" (TIF_FORK), \
108 [thread_info] "i" (offsetof(struct task_struct, stack)), \
109 [pda_pcurrent] "i" (offsetof(struct x8664_pda, pcurrent)) \
110 : "memory", "cc" __EXTRA_CLOBBER)
111#endif
112
113#ifdef __KERNEL__
114#define _set_base(addr, base) do { unsigned long __pr; \
115__asm__ __volatile__ ("movw %%dx,%1\n\t" \
116 "rorl $16,%%edx\n\t" \
117 "movb %%dl,%2\n\t" \
118 "movb %%dh,%3" \
119 :"=&d" (__pr) \
120 :"m" (*((addr)+2)), \
121 "m" (*((addr)+4)), \
122 "m" (*((addr)+7)), \
123 "0" (base) \
124 ); } while (0)
125
126#define _set_limit(addr, limit) do { unsigned long __lr; \
127__asm__ __volatile__ ("movw %%dx,%1\n\t" \
128 "rorl $16,%%edx\n\t" \
129 "movb %2,%%dh\n\t" \
130 "andb $0xf0,%%dh\n\t" \
131 "orb %%dh,%%dl\n\t" \
132 "movb %%dl,%2" \
133 :"=&d" (__lr) \
134 :"m" (*(addr)), \
135 "m" (*((addr)+6)), \
136 "0" (limit) \
137 ); } while (0)
138
139#define set_base(ldt, base) _set_base(((char *)&(ldt)) , (base))
140#define set_limit(ldt, limit) _set_limit(((char *)&(ldt)) , ((limit)-1))
141
142extern void native_load_gs_index(unsigned);
143
144
145
146
147
148#define loadsegment(seg, value) \
149 asm volatile("\n" \
150 "1:\t" \
151 "movl %k0,%%" #seg "\n" \
152 "2:\n" \
153 ".section .fixup,\"ax\"\n" \
154 "3:\t" \
155 "movl %k1, %%" #seg "\n\t" \
156 "jmp 2b\n" \
157 ".previous\n" \
158 _ASM_EXTABLE(1b,3b) \
159 : :"r" (value), "r" (0) : "memory")
160
161
162
163
164
165#define savesegment(seg, value) \
166 asm("mov %%" #seg ",%0":"=r" (value) : : "memory")
167
168static inline unsigned long get_limit(unsigned long segment)
169{
170 unsigned long __limit;
171 asm("lsll %1,%0" : "=r" (__limit) : "r" (segment));
172 return __limit + 1;
173}
174
175static inline void native_clts(void)
176{
177 asm volatile("clts");
178}
179
180
181
182
183
184
185
186
187static unsigned long __force_order;
188
189static inline unsigned long native_read_cr0(void)
190{
191 unsigned long val;
192 asm volatile("mov %%cr0,%0\n\t" : "=r" (val), "=m" (__force_order));
193 return val;
194}
195
196static inline void native_write_cr0(unsigned long val)
197{
198 asm volatile("mov %0,%%cr0": : "r" (val), "m" (__force_order));
199}
200
201static inline unsigned long native_read_cr2(void)
202{
203 unsigned long val;
204 asm volatile("mov %%cr2,%0\n\t" : "=r" (val), "=m" (__force_order));
205 return val;
206}
207
208static inline void native_write_cr2(unsigned long val)
209{
210 asm volatile("mov %0,%%cr2": : "r" (val), "m" (__force_order));
211}
212
213static inline unsigned long native_read_cr3(void)
214{
215 unsigned long val;
216 asm volatile("mov %%cr3,%0\n\t" : "=r" (val), "=m" (__force_order));
217 return val;
218}
219
220static inline void native_write_cr3(unsigned long val)
221{
222 asm volatile("mov %0,%%cr3": : "r" (val), "m" (__force_order));
223}
224
225static inline unsigned long native_read_cr4(void)
226{
227 unsigned long val;
228 asm volatile("mov %%cr4,%0\n\t" : "=r" (val), "=m" (__force_order));
229 return val;
230}
231
232static inline unsigned long native_read_cr4_safe(void)
233{
234 unsigned long val;
235
236
237#ifdef CONFIG_X86_32
238 asm volatile("1: mov %%cr4, %0\n"
239 "2:\n"
240 _ASM_EXTABLE(1b, 2b)
241 : "=r" (val), "=m" (__force_order) : "0" (0));
242#else
243 val = native_read_cr4();
244#endif
245 return val;
246}
247
248static inline void native_write_cr4(unsigned long val)
249{
250 asm volatile("mov %0,%%cr4": : "r" (val), "m" (__force_order));
251}
252
253#ifdef CONFIG_X86_64
254static inline unsigned long native_read_cr8(void)
255{
256 unsigned long cr8;
257 asm volatile("movq %%cr8,%0" : "=r" (cr8));
258 return cr8;
259}
260
261static inline void native_write_cr8(unsigned long val)
262{
263 asm volatile("movq %0,%%cr8" :: "r" (val) : "memory");
264}
265#endif
266
267static inline void native_wbinvd(void)
268{
269 asm volatile("wbinvd": : :"memory");
270}
271
272#ifdef CONFIG_PARAVIRT
273#include <asm/paravirt.h>
274#else
275#define read_cr0() (native_read_cr0())
276#define write_cr0(x) (native_write_cr0(x))
277#define read_cr2() (native_read_cr2())
278#define write_cr2(x) (native_write_cr2(x))
279#define read_cr3() (native_read_cr3())
280#define write_cr3(x) (native_write_cr3(x))
281#define read_cr4() (native_read_cr4())
282#define read_cr4_safe() (native_read_cr4_safe())
283#define write_cr4(x) (native_write_cr4(x))
284#define wbinvd() (native_wbinvd())
285#ifdef CONFIG_X86_64
286#define read_cr8() (native_read_cr8())
287#define write_cr8(x) (native_write_cr8(x))
288#define load_gs_index native_load_gs_index
289#endif
290
291
292#define clts() (native_clts())
293
294#endif
295
296#define stts() write_cr0(read_cr0() | X86_CR0_TS)
297
298#endif
299
300static inline void clflush(volatile void *__p)
301{
302 asm volatile("clflush %0" : "+m" (*(volatile char __force *)__p));
303}
304
305#define nop() asm volatile ("nop")
306
307void disable_hlt(void);
308void enable_hlt(void);
309
310void cpu_idle_wait(void);
311
312extern unsigned long arch_align_stack(unsigned long sp);
313extern void free_init_pages(char *what, unsigned long begin, unsigned long end);
314
315void default_idle(void);
316
317
318
319
320
321
322#ifdef CONFIG_X86_32
323
324
325
326
327#define mb() alternative("lock; addl $0,0(%%esp)", "mfence", X86_FEATURE_XMM2)
328#define rmb() alternative("lock; addl $0,0(%%esp)", "lfence", X86_FEATURE_XMM2)
329#define wmb() alternative("lock; addl $0,0(%%esp)", "sfence", X86_FEATURE_XMM)
330#else
331#define mb() asm volatile("mfence":::"memory")
332#define rmb() asm volatile("lfence":::"memory")
333#define wmb() asm volatile("sfence" ::: "memory")
334#endif
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388#define read_barrier_depends() do { } while (0)
389
390#ifdef CONFIG_SMP
391#define smp_mb() mb()
392#ifdef CONFIG_X86_PPRO_FENCE
393# define smp_rmb() rmb()
394#else
395# define smp_rmb() barrier()
396#endif
397#ifdef CONFIG_X86_OOSTORE
398# define smp_wmb() wmb()
399#else
400# define smp_wmb() barrier()
401#endif
402#define smp_read_barrier_depends() read_barrier_depends()
403#define set_mb(var, value) do { (void)xchg(&var, value); } while (0)
404#else
405#define smp_mb() barrier()
406#define smp_rmb() barrier()
407#define smp_wmb() barrier()
408#define smp_read_barrier_depends() do { } while (0)
409#define set_mb(var, value) do { var = value; barrier(); } while (0)
410#endif
411
412
413
414
415
416
417
418
419static inline void rdtsc_barrier(void)
420{
421 alternative(ASM_NOP3, "mfence", X86_FEATURE_MFENCE_RDTSC);
422 alternative(ASM_NOP3, "lfence", X86_FEATURE_LFENCE_RDTSC);
423}
424
425#endif
426