cpufunc.h revision 1.28.16.3 1 /* $NetBSD: cpufunc.h,v 1.28.16.3 2007/02/26 09:07:01 yamt Exp $ */
2
3 /*-
4 * Copyright (c) 1998 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Charles M. Hannum.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. All advertising materials mentioning features or use of this software
19 * must display the following acknowledgement:
20 * This product includes software developed by the NetBSD
21 * Foundation, Inc. and its contributors.
22 * 4. Neither the name of The NetBSD Foundation nor the names of its
23 * contributors may be used to endorse or promote products derived
24 * from this software without specific prior written permission.
25 *
26 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
27 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
28 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
30 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36 * POSSIBILITY OF SUCH DAMAGE.
37 */
38
39 #ifndef _I386_CPUFUNC_H_
40 #define _I386_CPUFUNC_H_
41
42 /*
43 * Functions to provide access to i386-specific instructions.
44 */
45
46 #include <sys/cdefs.h>
47 #include <sys/types.h>
48
49 #include <machine/segments.h>
50 #include <machine/specialreg.h>
51
52 #ifdef _KERNEL
53 void x86_pause(void);
54 #else
55 static __inline void
56 x86_pause(void)
57 {
58 __asm volatile("pause");
59 }
60 #endif
61
62 /*
63 * XXX it's better to use real lfence insn if available.
64 *
65 * memory clobber to avoid compiler reordering.
66 */
67 static __inline void
68 x86_lfence(void)
69 {
70
71 __asm volatile("lock; addl $0, 0(%%esp)" : : : "memory");
72 }
73
74 static __inline void
75 x86_sfence(void)
76 {
77
78 __asm volatile("lock; addl $0, 0(%%esp)" : : : "memory");
79 }
80
81 static __inline void
82 x86_mfence(void)
83 {
84
85 __asm volatile("lock; addl $0, 0(%%esp)" : : : "memory");
86 }
87
88 #ifdef _KERNEL
89
90 void x86_flush(void);
91 void x86_patch(void);
92
93 extern unsigned int cpu_feature;
94
95 static __inline void
96 invlpg(u_int addr)
97 {
98 __asm volatile("invlpg (%0)" : : "r" (addr) : "memory");
99 }
100
101 static __inline void
102 lidt(struct region_descriptor *region)
103 {
104 __asm volatile("lidt %0" : : "m" (*region));
105 }
106
107 static __inline void
108 lldt(u_short sel)
109 {
110 __asm volatile("lldt %0" : : "r" (sel));
111 }
112
113 static __inline void
114 ltr(u_short sel)
115 {
116 __asm volatile("ltr %0" : : "r" (sel));
117 }
118
119 static __inline void
120 lcr0(u_int val)
121 {
122 __asm volatile("movl %0,%%cr0" : : "r" (val));
123 }
124
125 static __inline u_int
126 rcr0(void)
127 {
128 u_int val;
129 __asm volatile("movl %%cr0,%0" : "=r" (val));
130 return val;
131 }
132
133 static __inline u_int
134 rcr2(void)
135 {
136 u_int val;
137 __asm volatile("movl %%cr2,%0" : "=r" (val));
138 return val;
139 }
140
141 static __inline void
142 lcr3(u_int val)
143 {
144 __asm volatile("movl %0,%%cr3" : : "r" (val));
145 }
146
147 static __inline u_int
148 rcr3(void)
149 {
150 u_int val;
151 __asm volatile("movl %%cr3,%0" : "=r" (val));
152 return val;
153 }
154
155 static __inline void
156 lcr4(u_int val)
157 {
158 __asm volatile("movl %0,%%cr4" : : "r" (val));
159 }
160
161 static __inline u_int
162 rcr4(void)
163 {
164 u_int val;
165 __asm volatile("movl %%cr4,%0" : "=r" (val));
166 return val;
167 }
168
169 static __inline void
170 tlbflush(void)
171 {
172 u_int val;
173 val = rcr3();
174 lcr3(val);
175 }
176
177 static __inline void
178 tlbflushg(void)
179 {
180 /*
181 * Big hammer: flush all TLB entries, including ones from PTE's
182 * with the G bit set. This should only be necessary if TLB
183 * shootdown falls far behind.
184 *
185 * Intel Architecture Software Developer's Manual, Volume 3,
186 * System Programming, section 9.10, "Invalidating the
187 * Translation Lookaside Buffers (TLBS)":
188 * "The following operations invalidate all TLB entries, irrespective
189 * of the setting of the G flag:
190 * ...
191 * "(P6 family processors only): Writing to control register CR4 to
192 * modify the PSE, PGE, or PAE flag."
193 *
194 * (the alternatives not quoted above are not an option here.)
195 *
196 * If PGE is not in use, we reload CR3 for the benefit of
197 * pre-P6-family processors.
198 */
199
200 #if defined(I686_CPU)
201 if (cpu_feature & CPUID_PGE) {
202 u_int cr4 = rcr4();
203 lcr4(cr4 & ~CR4_PGE);
204 lcr4(cr4);
205 } else
206 #endif
207 tlbflush();
208 }
209
210
211 #ifdef notyet
212 void setidt(int idx, /*XXX*/caddr_t func, int typ, int dpl);
213 #endif
214
215 /* debug register */
216 void dr0(caddr_t, uint32_t, uint32_t, uint32_t);
217
218 static __inline u_int
219 rdr6(void)
220 {
221 u_int val;
222
223 __asm volatile("movl %%dr6,%0" : "=r" (val));
224 return val;
225 }
226
227 static __inline void
228 ldr6(u_int val)
229 {
230
231 __asm volatile("movl %0,%%dr6" : : "r" (val));
232 }
233
234 /* XXXX ought to be in psl.h with spl() functions */
235
236 static __inline void
237 disable_intr(void)
238 {
239 __asm volatile("cli");
240 }
241
242 static __inline void
243 enable_intr(void)
244 {
245 __asm volatile("sti");
246 }
247
248 static __inline u_long
249 read_eflags(void)
250 {
251 u_long ef;
252
253 __asm volatile("pushfl; popl %0" : "=r" (ef));
254 return (ef);
255 }
256
257 static __inline void
258 write_eflags(u_long ef)
259 {
260 __asm volatile("pushl %0; popfl" : : "r" (ef));
261 }
262
263 static __inline uint64_t
264 rdmsr(u_int msr)
265 {
266 uint64_t rv;
267
268 __asm volatile("rdmsr" : "=A" (rv) : "c" (msr));
269 return (rv);
270 }
271
272 static __inline void
273 wrmsr(u_int msr, uint64_t newval)
274 {
275 __asm volatile("wrmsr" : : "A" (newval), "c" (msr));
276 }
277
278 /*
279 * Some of the undocumented AMD64 MSRs need a 'passcode' to access.
280 *
281 * See LinuxBIOSv2: src/cpu/amd/model_fxx/model_fxx_init.c
282 */
283
284 #define OPTERON_MSR_PASSCODE 0x9c5a203a
285
286 static __inline u_int64_t
287 rdmsr_locked(u_int msr, u_int code)
288 {
289 uint64_t rv;
290 __asm volatile("rdmsr"
291 : "=A" (rv)
292 : "c" (msr), "D" (code));
293 return (rv);
294 }
295
296 static __inline void
297 wrmsr_locked(u_int msr, u_int code, u_int64_t newval)
298 {
299 __asm volatile("wrmsr"
300 :
301 : "A" (newval), "c" (msr), "D" (code));
302 }
303
304 static __inline void
305 wbinvd(void)
306 {
307 __asm volatile("wbinvd");
308 }
309
310 static __inline uint64_t
311 rdtsc(void)
312 {
313 uint64_t rv;
314
315 __asm volatile("rdtsc" : "=A" (rv));
316 return (rv);
317 }
318
319 static __inline uint64_t
320 rdpmc(u_int pmc)
321 {
322 uint64_t rv;
323
324 __asm volatile("rdpmc" : "=A" (rv) : "c" (pmc));
325 return (rv);
326 }
327
328 /* Break into DDB/KGDB. */
329 static __inline void
330 breakpoint(void)
331 {
332 __asm volatile("int $3");
333 }
334
335 #define read_psl() read_eflags()
336 #define write_psl(x) write_eflags(x)
337
338 /*
339 * XXX Maybe these don't belong here...
340 */
341
342 extern int (*copyout_func)(const void *, void *, size_t);
343 extern int (*copyin_func)(const void *, void *, size_t);
344
345 int i386_copyout(const void *, void *, size_t);
346 int i486_copyout(const void *, void *, size_t);
347
348 int i386_copyin(const void *, void *, size_t);
349
350 #endif /* _KERNEL */
351
352 #endif /* !_I386_CPUFUNC_H_ */
353