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