2 * Copyright (c) 1993 The Regents of the University of California.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
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.
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
33 * $FreeBSD: src/sys/i386/include/cpufunc.h,v 1.96.2.3 2002/04/28 22:50:54 dwmalone Exp $
37 * Functions to provide access to special i386 instructions.
40 #ifndef _MACHINE_CPUFUNC_H_
41 #define _MACHINE_CPUFUNC_H_
43 #include <sys/cdefs.h>
46 #define readb(va) (*(volatile u_int8_t *) (va))
47 #define readw(va) (*(volatile u_int16_t *) (va))
48 #define readl(va) (*(volatile u_int32_t *) (va))
50 #define writeb(va, d) (*(volatile u_int8_t *) (va) = (d))
51 #define writew(va, d) (*(volatile u_int16_t *) (va) = (d))
52 #define writel(va, d) (*(volatile u_int32_t *) (va) = (d))
57 #include <machine/lock.h> /* XXX */
60 #ifdef SWTCH_OPTIM_STATS
61 extern int tlb_flush_count; /* XXX */
67 __asm __volatile("int $3");
75 __asm __volatile("bsfl %0,%0" : "=r" (result) : "0" (mask));
84 __asm __volatile("bsrl %0,%0" : "=r" (result) : "0" (mask));
91 __asm __volatile("cli" : : : "memory");
98 do_cpuid(u_int ax, u_int *p)
100 __asm __volatile("cpuid"
101 : "=a" (p[0]), "=b" (p[1]), "=c" (p[2]), "=d" (p[3])
111 __asm __volatile("sti");
114 #define HAVE_INLINE_FFS
120 * Note that gcc-2's builtin ffs would be used if we didn't declare
121 * this inline or turn off the builtin. The builtin is faster but
122 * broken in gcc-2.4.5 and slower but working in gcc-2.5 and later
125 return (mask == 0 ? mask : bsfl((u_int)mask) + 1);
128 #define HAVE_INLINE_FLS
133 return (mask == 0 ? mask : bsrl((u_int)mask) + 1);
138 #define inb(port) inbv(port)
139 #define outb(port, data) outbv(port, data)
141 #else /* __GNUC >= 2 */
144 * The following complications are to get around gcc not having a
145 * constraint letter for the range 0..255. We still put "d" in the
146 * constraint because "i" isn't a valid constraint when the port
147 * isn't constant. This only matters for -O0 because otherwise
148 * the non-working version gets optimized away.
150 * Use an expression-statement instead of a conditional expression
151 * because gcc-2.6.0 would promote the operands of the conditional
152 * and produce poor code for "if ((inb(var) & const1) == const2)".
154 * The unnecessary test `(port) < 0x10000' is to generate a warning if
155 * the `port' has type u_short or smaller. Such types are pessimal.
156 * This actually only works for signed types. The range check is
157 * careful to avoid generating warnings.
159 #define inb(port) __extension__ ({ \
161 if (__builtin_constant_p(port) && ((port) & 0xffff) < 0x100 \
162 && (port) < 0x10000) \
163 _data = inbc(port); \
165 _data = inbv(port); \
168 #define outb(port, data) ( \
169 __builtin_constant_p(port) && ((port) & 0xffff) < 0x100 \
170 && (port) < 0x10000 \
171 ? outbc(port, data) : outbv(port, data))
173 static __inline u_char
178 __asm __volatile("inb %1,%0" : "=a" (data) : "id" ((u_short)(port)));
183 outbc(u_int port, u_char data)
185 __asm __volatile("outb %0,%1" : : "a" (data), "id" ((u_short)(port)));
188 #endif /* __GNUC <= 2 */
190 static __inline u_char
195 * We use %%dx and not %1 here because i/o is done at %dx and not at
196 * %edx, while gcc generates inferior code (movw instead of movl)
197 * if we tell it to load (u_short) port.
199 __asm __volatile("inb %%dx,%0" : "=a" (data) : "d" (port));
203 static __inline u_int
208 __asm __volatile("inl %%dx,%0" : "=a" (data) : "d" (port));
213 insb(u_int port, void *addr, size_t cnt)
215 __asm __volatile("cld; rep; insb"
216 : "=D" (addr), "=c" (cnt)
217 : "0" (addr), "1" (cnt), "d" (port)
222 insw(u_int port, void *addr, size_t cnt)
224 __asm __volatile("cld; rep; insw"
225 : "=D" (addr), "=c" (cnt)
226 : "0" (addr), "1" (cnt), "d" (port)
231 insl(u_int port, void *addr, size_t cnt)
233 __asm __volatile("cld; rep; insl"
234 : "=D" (addr), "=c" (cnt)
235 : "0" (addr), "1" (cnt), "d" (port)
242 __asm __volatile("invd");
245 #if defined(SMP) && defined(_KERNEL)
248 * When using APIC IPI's, invlpg() is not simply the invlpg instruction
249 * (this is a bug) and the inlining cost is prohibitive since the call
250 * executes into the IPI transmission system.
252 void invlpg __P((u_int addr));
253 void invltlb __P((void));
256 cpu_invlpg(void *addr)
258 __asm __volatile("invlpg %0" : : "m" (*(char *)addr) : "memory");
266 * This should be implemented as load_cr3(rcr3()) when load_cr3()
269 __asm __volatile("movl %%cr3, %0; movl %0, %%cr3" : "=r" (temp)
271 #if defined(SWTCH_OPTIM_STATS)
276 #else /* !(SMP && _KERNEL) */
281 __asm __volatile("invlpg %0" : : "m" (*(char *)addr) : "memory");
289 * This should be implemented as load_cr3(rcr3()) when load_cr3()
292 __asm __volatile("movl %%cr3, %0; movl %0, %%cr3" : "=r" (temp)
294 #ifdef SWTCH_OPTIM_STATS
299 #endif /* SMP && _KERNEL */
301 static __inline u_short
306 __asm __volatile("inw %%dx,%0" : "=a" (data) : "d" (port));
310 static __inline u_int
311 loadandclear(volatile u_int *addr)
315 __asm __volatile("xorl %0,%0; xchgl %1,%0"
316 : "=&r" (result) : "m" (*addr));
321 outbv(u_int port, u_char data)
325 * Use an unnecessary assignment to help gcc's register allocator.
326 * This make a large difference for gcc-1.40 and a tiny difference
327 * for gcc-2.6.0. For gcc-1.40, al had to be ``asm("ax")'' for
328 * best results. gcc-2.6.0 can't handle this.
331 __asm __volatile("outb %0,%%dx" : : "a" (al), "d" (port));
335 outl(u_int port, u_int data)
338 * outl() and outw() aren't used much so we haven't looked at
339 * possible micro-optimizations such as the unnecessary
340 * assignment for them.
342 __asm __volatile("outl %0,%%dx" : : "a" (data), "d" (port));
346 outsb(u_int port, const void *addr, size_t cnt)
348 __asm __volatile("cld; rep; outsb"
349 : "=S" (addr), "=c" (cnt)
350 : "0" (addr), "1" (cnt), "d" (port));
354 outsw(u_int port, const void *addr, size_t cnt)
356 __asm __volatile("cld; rep; outsw"
357 : "=S" (addr), "=c" (cnt)
358 : "0" (addr), "1" (cnt), "d" (port));
362 outsl(u_int port, const void *addr, size_t cnt)
364 __asm __volatile("cld; rep; outsl"
365 : "=S" (addr), "=c" (cnt)
366 : "0" (addr), "1" (cnt), "d" (port));
370 outw(u_int port, u_short data)
372 __asm __volatile("outw %0,%%dx" : : "a" (data), "d" (port));
375 static __inline u_int
380 __asm __volatile("movl %%cr2,%0" : "=r" (data));
384 static __inline u_int
389 __asm __volatile("pushfl; popl %0" : "=r" (ef));
393 static __inline u_int64_t
398 __asm __volatile(".byte 0x0f, 0x32" : "=A" (rv) : "c" (msr));
402 static __inline u_int64_t
407 __asm __volatile(".byte 0x0f, 0x33" : "=A" (rv) : "c" (pmc));
411 static __inline u_int64_t
416 __asm __volatile(".byte 0x0f, 0x31" : "=A" (rv));
423 __asm __volatile("wbinvd");
427 write_eflags(u_int ef)
429 __asm __volatile("pushl %0; popfl" : : "r" (ef));
433 wrmsr(u_int msr, u_int64_t newval)
435 __asm __volatile(".byte 0x0f, 0x30" : : "A" (newval), "c" (msr));
438 static __inline u_int
442 __asm __volatile("movl %%fs,%0" : "=rm" (sel));
446 static __inline u_int
450 __asm __volatile("movl %%gs,%0" : "=rm" (sel));
457 __asm __volatile("movl %0,%%fs" : : "rm" (sel));
463 __asm __volatile("movl %0,%%gs" : : "rm" (sel));
466 static __inline u_int
470 __asm __volatile("movl %%dr0,%0" : "=r" (data));
477 __asm __volatile("movl %0,%%dr0" : : "r" (sel));
480 static __inline u_int
484 __asm __volatile("movl %%dr1,%0" : "=r" (data));
491 __asm __volatile("movl %0,%%dr1" : : "r" (sel));
494 static __inline u_int
498 __asm __volatile("movl %%dr2,%0" : "=r" (data));
505 __asm __volatile("movl %0,%%dr2" : : "r" (sel));
508 static __inline u_int
512 __asm __volatile("movl %%dr3,%0" : "=r" (data));
519 __asm __volatile("movl %0,%%dr3" : : "r" (sel));
522 static __inline u_int
526 __asm __volatile("movl %%dr4,%0" : "=r" (data));
533 __asm __volatile("movl %0,%%dr4" : : "r" (sel));
536 static __inline u_int
540 __asm __volatile("movl %%dr5,%0" : "=r" (data));
547 __asm __volatile("movl %0,%%dr5" : : "r" (sel));
550 static __inline u_int
554 __asm __volatile("movl %%dr6,%0" : "=r" (data));
561 __asm __volatile("movl %0,%%dr6" : : "r" (sel));
564 static __inline u_int
568 __asm __volatile("movl %%dr7,%0" : "=r" (data));
575 __asm __volatile("movl %0,%%dr7" : : "r" (sel));
578 #else /* !__GNUC__ */
580 int breakpoint __P((void));
581 u_int bsfl __P((u_int mask));
582 u_int bsrl __P((u_int mask));
583 void disable_intr __P((void));
584 void do_cpuid __P((u_int ax, u_int *p));
585 void enable_intr __P((void));
586 u_char inb __P((u_int port));
587 u_int inl __P((u_int port));
588 void insb __P((u_int port, void *addr, size_t cnt));
589 void insl __P((u_int port, void *addr, size_t cnt));
590 void insw __P((u_int port, void *addr, size_t cnt));
591 void invd __P((void));
592 void invlpg __P((u_int addr));
593 void invltlb __P((void));
594 u_short inw __P((u_int port));
595 u_int loadandclear __P((u_int *addr));
596 void outb __P((u_int port, u_char data));
597 void outl __P((u_int port, u_int data));
598 void outsb __P((u_int port, void *addr, size_t cnt));
599 void outsl __P((u_int port, void *addr, size_t cnt));
600 void outsw __P((u_int port, void *addr, size_t cnt));
601 void outw __P((u_int port, u_short data));
602 u_int rcr2 __P((void));
603 u_int64_t rdmsr __P((u_int msr));
604 u_int64_t rdpmc __P((u_int pmc));
605 u_int64_t rdtsc __P((void));
606 u_int read_eflags __P((void));
607 void wbinvd __P((void));
608 void write_eflags __P((u_int ef));
609 void wrmsr __P((u_int msr, u_int64_t newval));
610 u_int rfs __P((void));
611 u_int rgs __P((void));
612 void load_fs __P((u_int sel));
613 void load_gs __P((u_int sel));
615 #endif /* __GNUC__ */
617 void load_cr0 __P((u_int cr0));
618 void load_cr3 __P((u_int cr3));
619 void load_cr4 __P((u_int cr4));
620 void ltr __P((u_short sel));
621 u_int rcr0 __P((void));
622 u_int rcr3 __P((void));
623 u_int rcr4 __P((void));
624 void reset_dbregs __P((void));
627 #endif /* !_MACHINE_CPUFUNC_H_ */