Commit | Line | Data |
---|---|---|
f05e798a DH |
1 | #ifndef _ASM_X86_SPECIAL_INSNS_H |
2 | #define _ASM_X86_SPECIAL_INSNS_H | |
3 | ||
4 | ||
5 | #ifdef __KERNEL__ | |
6 | ||
7 | static inline void native_clts(void) | |
8 | { | |
9 | asm volatile("clts"); | |
10 | } | |
11 | ||
12 | /* | |
13 | * Volatile isn't enough to prevent the compiler from reordering the | |
14 | * read/write functions for the control registers and messing everything up. | |
15 | * A memory clobber would solve the problem, but would prevent reordering of | |
16 | * all loads stores around it, which can hurt performance. Solution is to | |
17 | * use a variable and mimic reads and writes to it to enforce serialization | |
18 | */ | |
1d10f6ee | 19 | extern unsigned long __force_order; |
f05e798a DH |
20 | |
21 | static inline unsigned long native_read_cr0(void) | |
22 | { | |
23 | unsigned long val; | |
24 | asm volatile("mov %%cr0,%0\n\t" : "=r" (val), "=m" (__force_order)); | |
25 | return val; | |
26 | } | |
27 | ||
28 | static inline void native_write_cr0(unsigned long val) | |
29 | { | |
30 | asm volatile("mov %0,%%cr0": : "r" (val), "m" (__force_order)); | |
31 | } | |
32 | ||
33 | static inline unsigned long native_read_cr2(void) | |
34 | { | |
35 | unsigned long val; | |
36 | asm volatile("mov %%cr2,%0\n\t" : "=r" (val), "=m" (__force_order)); | |
37 | return val; | |
38 | } | |
39 | ||
40 | static inline void native_write_cr2(unsigned long val) | |
41 | { | |
42 | asm volatile("mov %0,%%cr2": : "r" (val), "m" (__force_order)); | |
43 | } | |
44 | ||
45 | static inline unsigned long native_read_cr3(void) | |
46 | { | |
47 | unsigned long val; | |
48 | asm volatile("mov %%cr3,%0\n\t" : "=r" (val), "=m" (__force_order)); | |
49 | return val; | |
50 | } | |
51 | ||
52 | static inline void native_write_cr3(unsigned long val) | |
53 | { | |
54 | asm volatile("mov %0,%%cr3": : "r" (val), "m" (__force_order)); | |
55 | } | |
56 | ||
57 | static inline unsigned long native_read_cr4(void) | |
58 | { | |
59 | unsigned long val; | |
60 | asm volatile("mov %%cr4,%0\n\t" : "=r" (val), "=m" (__force_order)); | |
61 | return val; | |
62 | } | |
63 | ||
64 | static inline unsigned long native_read_cr4_safe(void) | |
65 | { | |
66 | unsigned long val; | |
67 | /* This could fault if %cr4 does not exist. In x86_64, a cr4 always | |
68 | * exists, so it will never fail. */ | |
69 | #ifdef CONFIG_X86_32 | |
70 | asm volatile("1: mov %%cr4, %0\n" | |
71 | "2:\n" | |
72 | _ASM_EXTABLE(1b, 2b) | |
73 | : "=r" (val), "=m" (__force_order) : "0" (0)); | |
74 | #else | |
75 | val = native_read_cr4(); | |
76 | #endif | |
77 | return val; | |
78 | } | |
79 | ||
80 | static inline void native_write_cr4(unsigned long val) | |
81 | { | |
82 | asm volatile("mov %0,%%cr4": : "r" (val), "m" (__force_order)); | |
83 | } | |
84 | ||
85 | #ifdef CONFIG_X86_64 | |
86 | static inline unsigned long native_read_cr8(void) | |
87 | { | |
88 | unsigned long cr8; | |
89 | asm volatile("movq %%cr8,%0" : "=r" (cr8)); | |
90 | return cr8; | |
91 | } | |
92 | ||
93 | static inline void native_write_cr8(unsigned long val) | |
94 | { | |
95 | asm volatile("movq %0,%%cr8" :: "r" (val) : "memory"); | |
96 | } | |
97 | #endif | |
98 | ||
99 | static inline void native_wbinvd(void) | |
100 | { | |
101 | asm volatile("wbinvd": : :"memory"); | |
102 | } | |
103 | ||
277d5b40 | 104 | extern asmlinkage void native_load_gs_index(unsigned); |
f05e798a DH |
105 | |
106 | #ifdef CONFIG_PARAVIRT | |
107 | #include <asm/paravirt.h> | |
108 | #else | |
109 | ||
110 | static inline unsigned long read_cr0(void) | |
111 | { | |
112 | return native_read_cr0(); | |
113 | } | |
114 | ||
115 | static inline void write_cr0(unsigned long x) | |
116 | { | |
117 | native_write_cr0(x); | |
118 | } | |
119 | ||
120 | static inline unsigned long read_cr2(void) | |
121 | { | |
122 | return native_read_cr2(); | |
123 | } | |
124 | ||
125 | static inline void write_cr2(unsigned long x) | |
126 | { | |
127 | native_write_cr2(x); | |
128 | } | |
129 | ||
130 | static inline unsigned long read_cr3(void) | |
131 | { | |
132 | return native_read_cr3(); | |
133 | } | |
134 | ||
135 | static inline void write_cr3(unsigned long x) | |
136 | { | |
137 | native_write_cr3(x); | |
138 | } | |
139 | ||
140 | static inline unsigned long read_cr4(void) | |
141 | { | |
142 | return native_read_cr4(); | |
143 | } | |
144 | ||
145 | static inline unsigned long read_cr4_safe(void) | |
146 | { | |
147 | return native_read_cr4_safe(); | |
148 | } | |
149 | ||
150 | static inline void write_cr4(unsigned long x) | |
151 | { | |
152 | native_write_cr4(x); | |
153 | } | |
154 | ||
155 | static inline void wbinvd(void) | |
156 | { | |
157 | native_wbinvd(); | |
158 | } | |
159 | ||
160 | #ifdef CONFIG_X86_64 | |
161 | ||
162 | static inline unsigned long read_cr8(void) | |
163 | { | |
164 | return native_read_cr8(); | |
165 | } | |
166 | ||
167 | static inline void write_cr8(unsigned long x) | |
168 | { | |
169 | native_write_cr8(x); | |
170 | } | |
171 | ||
172 | static inline void load_gs_index(unsigned selector) | |
173 | { | |
174 | native_load_gs_index(selector); | |
175 | } | |
176 | ||
177 | #endif | |
178 | ||
179 | /* Clear the 'TS' bit */ | |
180 | static inline void clts(void) | |
181 | { | |
182 | native_clts(); | |
183 | } | |
184 | ||
185 | #endif/* CONFIG_PARAVIRT */ | |
186 | ||
187 | #define stts() write_cr0(read_cr0() | X86_CR0_TS) | |
188 | ||
189 | static inline void clflush(volatile void *__p) | |
190 | { | |
191 | asm volatile("clflush %0" : "+m" (*(volatile char __force *)__p)); | |
192 | } | |
193 | ||
194 | #define nop() asm volatile ("nop") | |
195 | ||
196 | ||
197 | #endif /* __KERNEL__ */ | |
198 | ||
199 | #endif /* _ASM_X86_SPECIAL_INSNS_H */ |