1 /*-
2 * Copyright (c) 1993 The Regents of the University of California.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 * must display the following acknowledgement:
15 * This product includes software developed by the University of
16 * California, Berkeley and its contributors.
17 * 4. Neither the name of the University nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 *
33 * $FreeBSD: src/sys/i386/include/cpufunc.h,v 1.59.2.3 1999/09/05 08:11:44 peter Exp $
34 */
35
36 /*
37 * Functions to provide access to special i386 instructions.
38 */
39
40 #ifndef _MACHINE_CPUFUNC_H_
41 #define _MACHINE_CPUFUNC_H_
42
43 #include <sys/cdefs.h>
44 #include <sys/types.h>
45
46 #ifdef __GNUC__
47
48 static __inline void
49 breakpoint(void)
50 {
51 __asm __volatile("int $3");
52 }
53
54 static __inline void
55 disable_intr(void)
56 {
57 __asm __volatile("cli" : : : "memory");
58 }
59
60 static __inline void
61 enable_intr(void)
62 {
63 __asm __volatile("sti");
64 }
65
66 #define HAVE_INLINE_FFS
67
68 static __inline int
69 ffs(int mask)
70 {
71 int result;
72 /*
73 * bsfl turns out to be not all that slow on 486's. It can beaten
74 * using a binary search to reduce to 4 bits and then a table lookup,
75 * but only if the code is inlined and in the cache, and the code
76 * is quite large so inlining it probably busts the cache.
77 *
78 * Note that gcc-2's builtin ffs would be used if we didn't declare
79 * this inline or turn off the builtin. The builtin is faster but
80 * broken in gcc-2.4.5 and slower but working in gcc-2.5 and 2.6.
81 */
82 __asm __volatile("testl %0,%0; je 1f; bsfl %0,%0; incl %0; 1:"
83 : "=r" (result) : "" (mask));
84 return (result);
85 }
86
87 #define HAVE_INLINE_FLS
88
89 static __inline int
90 fls(int mask)
91 {
92 int result;
93 __asm __volatile("testl %0,%0; je 1f; bsrl %0,%0; incl %0; 1:"
94 : "=r" (result) : "" (mask));
95 return (result);
96 }
97
98 #if __GNUC__ < 2
99
100 #define inb(port) inbv(port)
101 #define outb(port, data) outbv(port, data)
102
103 #else /* __GNUC >= 2 */
104
105 /*
106 * The following complications are to get around gcc not having a
107 * constraint letter for the range 0..255. We still put "d" in the
108 * constraint because "i" isn't a valid constraint when the port
109 * isn't constant. This only matters for -O0 because otherwise
110 * the non-working version gets optimized away.
111 *
112 * Use an expression-statement instead of a conditional expression
113 * because gcc-2.6.0 would promote the operands of the conditional
114 * and produce poor code for "if ((inb(var) & const1) == const2)".
115 *
116 * The unnecessary test `(port) < 0x10000' is to generate a warning if
117 * the `port' has type u_short or smaller. Such types are pessimal.
118 * This actually only works for signed types. The range check is
119 * careful to avoid generating warnings.
120 */
121 #define inb(port) __extension__ ({ \
122 u_char _data; \
123 if (__builtin_constant_p(port) && ((port) & 0xffff) < 0x100 \
124 && (port) < 0x10000) \
125 _data = inbc(port); \
126 else \
127 _data = inbv(port); \
128 _data; })
129
130 #define outb(port, data) ( \
131 __builtin_constant_p(port) && ((port) & 0xffff) < 0x100 \
132 && (port) < 0x10000 \
133 ? outbc(port, data) : outbv(port, data))
134
135 static __inline u_char
136 inbc(u_int port)
137 {
138 u_char data;
139
140 __asm __volatile("inb %1,%0" : "=a" (data) : "id" ((u_short)(port)));
141 return (data);
142 }
143
144 static __inline void
145 outbc(u_int port, u_char data)
146 {
147 __asm __volatile("outb %0,%1" : : "a" (data), "id" ((u_short)(port)));
148 }
149
150 #endif /* __GNUC <= 2 */
151
152 static __inline u_char
153 inbv(u_int port)
154 {
155 u_char data;
156 /*
157 * We use %%dx and not %1 here because i/o is done at %dx and not at
158 * %edx, while gcc generates inferior code (movw instead of movl)
159 * if we tell it to load (u_short) port.
160 */
161 __asm __volatile("inb %%dx,%0" : "=a" (data) : "d" (port));
162 return (data);
163 }
164
165 static __inline u_long
166 inl(u_int port)
167 {
168 u_long data;
169
170 __asm __volatile("inl %%dx,%0" : "=a" (data) : "d" (port));
171 return (data);
172 }
173
174 static __inline void
175 insb(u_int port, void *addr, size_t cnt)
176 {
177 __asm __volatile("cld; rep; insb"
178 : : "d" (port), "D" (addr), "c" (cnt)
179 : "di", "cx", "memory");
180 }
181
182 static __inline void
183 insw(u_int port, void *addr, size_t cnt)
184 {
185 __asm __volatile("cld; rep; insw"
186 : : "d" (port), "D" (addr), "c" (cnt)
187 : "di", "cx", "memory");
188 }
189
190 static __inline void
191 insl(u_int port, void *addr, size_t cnt)
192 {
193 __asm __volatile("cld; rep; insl"
194 : : "d" (port), "D" (addr), "c" (cnt)
195 : "di", "cx", "memory");
196 }
197
198 static __inline void
199 invd(void)
200 {
201 __asm __volatile("invd");
202 }
203
204 static __inline void
205 invlpg(u_int addr)
206 {
207 __asm __volatile("invlpg (%0)" : : "r" (addr) : "memory");
208 }
209
210 static __inline void
211 invltlb(void)
212 {
213 u_long temp;
214 /*
215 * This should be implemented as load_cr3(rcr3()) when load_cr3()
216 * is inlined.
217 */
218 __asm __volatile("movl %%cr3, %0; movl %0, %%cr3" : "=r" (temp)
219 : : "memory");
220 }
221
222 static __inline u_short
223 inw(u_int port)
224 {
225 u_short data;
226
227 __asm __volatile("inw %%dx,%0" : "=a" (data) : "d" (port));
228 return (data);
229 }
230
231 static __inline u_int
232 loadandclear(u_int *addr)
233 {
234 u_int result;
235
236 __asm __volatile("xorl %0,%0; xchgl %1,%0"
237 : "=&r" (result) : "m" (*addr));
238 return (result);
239 }
240
241 static __inline void
242 outbv(u_int port, u_char data)
243 {
244 u_char al;
245 /*
246 * Use an unnecessary assignment to help gcc's register allocator.
247 * This make a large difference for gcc-1.40 and a tiny difference
248 * for gcc-2.6.0. For gcc-1.40, al had to be ``asm("ax")'' for
249 * best results. gcc-2.6.0 can't handle this.
250 */
251 al = data;
252 __asm __volatile("outb %0,%%dx" : : "a" (al), "d" (port));
253 }
254
255 static __inline void
256 outl(u_int port, u_long data)
257 {
258 /*
259 * outl() and outw() aren't used much so we haven't looked at
260 * possible micro-optimizations such as the unnecessary
261 * assignment for them.
262 */
263 __asm __volatile("outl %0,%%dx" : : "a" (data), "d" (port));
264 }
265
266 static __inline void
267 outsb(u_int port, const void *addr, size_t cnt)
268 {
269 __asm __volatile("cld; rep; outsb"
270 : : "d" (port), "S" (addr), "c" (cnt)
271 : "si", "cx");
272 }
273
274 static __inline void
275 outsw(u_int port, const void *addr, size_t cnt)
276 {
277 __asm __volatile("cld; rep; outsw"
278 : : "d" (port), "S" (addr), "c" (cnt)
279 : "si", "cx");
280 }
281
282 static __inline void
283 outsl(u_int port, const void *addr, size_t cnt)
284 {
285 __asm __volatile("cld; rep; outsl"
286 : : "d" (port), "S" (addr), "c" (cnt)
287 : "si", "cx");
288 }
289
290 static __inline void
291 outw(u_int port, u_short data)
292 {
293 __asm __volatile("outw %0,%%dx" : : "a" (data), "d" (port));
294 }
295
296 static __inline u_long
297 rcr2(void)
298 {
299 u_long data;
300
301 __asm __volatile("movl %%cr2,%0" : "=r" (data));
302 return (data);
303 }
304
305 static __inline u_long
306 read_eflags(void)
307 {
308 u_long ef;
309
310 __asm __volatile("pushfl; popl %0" : "=r" (ef));
311 return (ef);
312 }
313
314 static __inline quad_t
315 rdmsr(u_int msr)
316 {
317 quad_t rv;
318
319 __asm __volatile(".byte 0x0f, 0x32" : "=A" (rv) : "c" (msr));
320 return (rv);
321 }
322
323 static __inline quad_t
324 rdpmc(u_int pmc)
325 {
326 quad_t rv;
327
328 __asm __volatile(".byte 0x0f, 0x33" : "=A" (rv) : "c" (pmc));
329 return (rv);
330 }
331
332 static __inline quad_t
333 rdtsc(void)
334 {
335 quad_t rv;
336
337 __asm __volatile(".byte 0x0f, 0x31" : "=A" (rv));
338 return (rv);
339 }
340
341 static __inline void
342 setbits(volatile unsigned *addr, u_int bits)
343 {
344 __asm __volatile("orl %1,%0" : "=m" (*addr) : "ir" (bits));
345 }
346
347 static __inline void
348 wbinvd(void)
349 {
350 __asm __volatile("wbinvd");
351 }
352
353 static __inline void
354 write_eflags(u_long ef)
355 {
356 __asm __volatile("pushl %0; popfl" : : "r" (ef));
357 }
358
359 static __inline void
360 wrmsr(u_int msr, quad_t newval)
361 {
362 __asm __volatile(".byte 0x0f, 0x30" : : "A" (newval), "c" (msr));
363 }
364
365 #else /* !__GNUC__ */
366
367 int breakpoint __P((void));
368 void disable_intr __P((void));
369 void enable_intr __P((void));
370 u_char inb __P((u_int port));
371 u_long inl __P((u_int port));
372 void insb __P((u_int port, void *addr, size_t cnt));
373 void insl __P((u_int port, void *addr, size_t cnt));
374 void insw __P((u_int port, void *addr, size_t cnt));
375 void invd __P((void));
376 void invlpg __P((u_int addr));
377 void invltlb __P((void));
378 u_short inw __P((u_int port));
379 u_int loadandclear __P((u_int *addr));
380 void outb __P((u_int port, u_char data));
381 void outl __P((u_int port, u_long data));
382 void outsb __P((u_int port, void *addr, size_t cnt));
383 void outsl __P((u_int port, void *addr, size_t cnt));
384 void outsw __P((u_int port, void *addr, size_t cnt));
385 void outw __P((u_int port, u_short data));
386 u_long rcr2 __P((void));
387 quad_t rdmsr __P((u_int msr));
388 quad_t rdpmc __P((u_int pmc));
389 quad_t rdtsc __P((void));
390 u_long read_eflags __P((void));
391 void setbits __P((volatile unsigned *addr, u_int bits));
392 void wbinvd __P((void));
393 void write_eflags __P((u_long ef));
394 void wrmsr __P((u_int msr, quad_t newval));
395
396 #endif /* __GNUC__ */
397
398 void load_cr0 __P((u_long cr0));
399 void load_cr3 __P((u_long cr3));
400 void ltr __P((u_short sel));
401 u_int rcr0 __P((void));
402 u_long rcr3 __P((void));
403
404 #include <machine/spl.h> /* XXX belongs elsewhere */
405
406 #endif /* !_MACHINE_CPUFUNC_H_ */
Cache object: 9f1d700b7921aa1299419e8567208d39
|