xref: /freebsd/sys/amd64/include/cpufunc.h (revision d85631c4ac29e17917c0444837225df309fba37e)
13c4dd356SDavid Greenman /*-
23c4dd356SDavid Greenman  * Copyright (c) 1993 The Regents of the University of California.
33c4dd356SDavid Greenman  * All rights reserved.
43c4dd356SDavid Greenman  *
53c4dd356SDavid Greenman  * Redistribution and use in source and binary forms, with or without
63c4dd356SDavid Greenman  * modification, are permitted provided that the following conditions
73c4dd356SDavid Greenman  * are met:
83c4dd356SDavid Greenman  * 1. Redistributions of source code must retain the above copyright
93c4dd356SDavid Greenman  *    notice, this list of conditions and the following disclaimer.
103c4dd356SDavid Greenman  * 2. Redistributions in binary form must reproduce the above copyright
113c4dd356SDavid Greenman  *    notice, this list of conditions and the following disclaimer in the
123c4dd356SDavid Greenman  *    documentation and/or other materials provided with the distribution.
133c4dd356SDavid Greenman  * 3. All advertising materials mentioning features or use of this software
143c4dd356SDavid Greenman  *    must display the following acknowledgement:
153c4dd356SDavid Greenman  *	This product includes software developed by the University of
163c4dd356SDavid Greenman  *	California, Berkeley and its contributors.
173c4dd356SDavid Greenman  * 4. Neither the name of the University nor the names of its contributors
183c4dd356SDavid Greenman  *    may be used to endorse or promote products derived from this software
193c4dd356SDavid Greenman  *    without specific prior written permission.
203c4dd356SDavid Greenman  *
213c4dd356SDavid Greenman  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
223c4dd356SDavid Greenman  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
233c4dd356SDavid Greenman  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
243c4dd356SDavid Greenman  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
253c4dd356SDavid Greenman  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
263c4dd356SDavid Greenman  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
273c4dd356SDavid Greenman  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
283c4dd356SDavid Greenman  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
293c4dd356SDavid Greenman  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
303c4dd356SDavid Greenman  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
313c4dd356SDavid Greenman  * SUCH DAMAGE.
323c4dd356SDavid Greenman  *
33c3aac50fSPeter Wemm  * $FreeBSD$
343c4dd356SDavid Greenman  */
353c4dd356SDavid Greenman 
365b81b6b3SRodney W. Grimes /*
375b81b6b3SRodney W. Grimes  * Functions to provide access to special i386 instructions.
38f5d9a10bSMark Murray  * This in included in sys/systm.h, and that file should be
39f5d9a10bSMark Murray  * used in preference to this.
405b81b6b3SRodney W. Grimes  */
415b81b6b3SRodney W. Grimes 
426e393973SGarrett Wollman #ifndef _MACHINE_CPUFUNC_H_
43004bedebSBruce Evans #define	_MACHINE_CPUFUNC_H_
446e393973SGarrett Wollman 
4529d5de8aSWarner Losh #include <sys/cdefs.h>
467e1f6dfeSJohn Baldwin #include <machine/psl.h>
4729d5de8aSWarner Losh 
48d74ac681SMatthew Dillon struct thread;
49eb1443c8SPeter Wemm struct region_descriptor;
50d74ac681SMatthew Dillon 
5129d5de8aSWarner Losh __BEGIN_DECLS
52e31fa854SDoug Rabson #define readb(va)	(*(volatile u_int8_t *) (va))
53e31fa854SDoug Rabson #define readw(va)	(*(volatile u_int16_t *) (va))
54e31fa854SDoug Rabson #define readl(va)	(*(volatile u_int32_t *) (va))
55afa88623SPeter Wemm #define readq(va)	(*(volatile u_int64_t *) (va))
56e31fa854SDoug Rabson 
57e31fa854SDoug Rabson #define writeb(va, d)	(*(volatile u_int8_t *) (va) = (d))
58e31fa854SDoug Rabson #define writew(va, d)	(*(volatile u_int16_t *) (va) = (d))
59e31fa854SDoug Rabson #define writel(va, d)	(*(volatile u_int32_t *) (va) = (d))
60afa88623SPeter Wemm #define writeq(va, d)	(*(volatile u_int64_t *) (va) = (d))
61e31fa854SDoug Rabson 
625b81b6b3SRodney W. Grimes #ifdef	__GNUC__
635b81b6b3SRodney W. Grimes 
645dbd168eSBruce Evans static __inline void
655dbd168eSBruce Evans breakpoint(void)
66004bedebSBruce Evans {
67004bedebSBruce Evans 	__asm __volatile("int $3");
685b81b6b3SRodney W. Grimes }
695b81b6b3SRodney W. Grimes 
70c83b1328SBruce Evans static __inline u_int
71c83b1328SBruce Evans bsfl(u_int mask)
72c83b1328SBruce Evans {
73c83b1328SBruce Evans 	u_int	result;
74c83b1328SBruce Evans 
753f9a462fSJohn Baldwin 	__asm __volatile("bsfl %1,%0" : "=r" (result) : "rm" (mask));
76c83b1328SBruce Evans 	return (result);
77c83b1328SBruce Evans }
78c83b1328SBruce Evans 
79c83b1328SBruce Evans static __inline u_int
80c83b1328SBruce Evans bsrl(u_int mask)
81c83b1328SBruce Evans {
82c83b1328SBruce Evans 	u_int	result;
83c83b1328SBruce Evans 
843f9a462fSJohn Baldwin 	__asm __volatile("bsrl %1,%0" : "=r" (result) : "rm" (mask));
85c83b1328SBruce Evans 	return (result);
86c83b1328SBruce Evans }
87c83b1328SBruce Evans 
88004bedebSBruce Evans static __inline void
895b81b6b3SRodney W. Grimes disable_intr(void)
905b81b6b3SRodney W. Grimes {
918966b85cSJohn Dyson 	__asm __volatile("cli" : : : "memory");
925b81b6b3SRodney W. Grimes }
935b81b6b3SRodney W. Grimes 
94004bedebSBruce Evans static __inline void
95a983fdfeSDavid Malone do_cpuid(u_int ax, u_int *p)
96a983fdfeSDavid Malone {
97a983fdfeSDavid Malone 	__asm __volatile("cpuid"
98a983fdfeSDavid Malone 			 : "=a" (p[0]), "=b" (p[1]), "=c" (p[2]), "=d" (p[3])
99a983fdfeSDavid Malone 			 :  "0" (ax));
100a983fdfeSDavid Malone }
101a983fdfeSDavid Malone 
102a983fdfeSDavid Malone static __inline void
1035b81b6b3SRodney W. Grimes enable_intr(void)
1045b81b6b3SRodney W. Grimes {
105fadc51bdSBruce Evans 	__asm __volatile("sti");
1065b81b6b3SRodney W. Grimes }
1075b81b6b3SRodney W. Grimes 
108264c3d87SPeter Wemm #define	HAVE_INLINE_FFS
109264c3d87SPeter Wemm 
110264c3d87SPeter Wemm static __inline int
111264c3d87SPeter Wemm ffs(int mask)
112264c3d87SPeter Wemm {
113264c3d87SPeter Wemm 	/*
114004bedebSBruce Evans 	 * Note that gcc-2's builtin ffs would be used if we didn't declare
115004bedebSBruce Evans 	 * this inline or turn off the builtin.  The builtin is faster but
116c83b1328SBruce Evans 	 * broken in gcc-2.4.5 and slower but working in gcc-2.5 and later
117c83b1328SBruce Evans 	 * versions.
118004bedebSBruce Evans 	 */
1197e622d3cSMark Murray 	 return (mask == 0 ? mask : (int)bsfl((u_int)mask) + 1);
120004bedebSBruce Evans }
121004bedebSBruce Evans 
12213f588f8SGarrett Wollman #define	HAVE_INLINE_FLS
12313f588f8SGarrett Wollman 
12413f588f8SGarrett Wollman static __inline int
12513f588f8SGarrett Wollman fls(int mask)
12613f588f8SGarrett Wollman {
1277e622d3cSMark Murray 	return (mask == 0 ? mask : (int)bsrl((u_int)mask) + 1);
12813f588f8SGarrett Wollman }
12913f588f8SGarrett Wollman 
130d7ee4425SMark Murray static __inline void
131d7ee4425SMark Murray halt(void)
132d7ee4425SMark Murray {
133d7ee4425SMark Murray 	__asm __volatile("hlt");
134d7ee4425SMark Murray }
135d7ee4425SMark Murray 
136004bedebSBruce Evans #if __GNUC__ < 2
137004bedebSBruce Evans 
138004bedebSBruce Evans #define	inb(port)		inbv(port)
139004bedebSBruce Evans #define	outb(port, data)	outbv(port, data)
140004bedebSBruce Evans 
141004bedebSBruce Evans #else /* __GNUC >= 2 */
142004bedebSBruce Evans 
143004bedebSBruce Evans /*
1448089a043SBruce Evans  * The following complications are to get around gcc not having a
1458089a043SBruce Evans  * constraint letter for the range 0..255.  We still put "d" in the
1468089a043SBruce Evans  * constraint because "i" isn't a valid constraint when the port
1478089a043SBruce Evans  * isn't constant.  This only matters for -O0 because otherwise
1488089a043SBruce Evans  * the non-working version gets optimized away.
1498089a043SBruce Evans  *
150004bedebSBruce Evans  * Use an expression-statement instead of a conditional expression
151004bedebSBruce Evans  * because gcc-2.6.0 would promote the operands of the conditional
152004bedebSBruce Evans  * and produce poor code for "if ((inb(var) & const1) == const2)".
153388dfa71SBruce Evans  *
154388dfa71SBruce Evans  * The unnecessary test `(port) < 0x10000' is to generate a warning if
155388dfa71SBruce Evans  * the `port' has type u_short or smaller.  Such types are pessimal.
156388dfa71SBruce Evans  * This actually only works for signed types.  The range check is
157388dfa71SBruce Evans  * careful to avoid generating warnings.
158004bedebSBruce Evans  */
159388dfa71SBruce Evans #define	inb(port) __extension__ ({					\
160004bedebSBruce Evans 	u_char	_data;							\
161388dfa71SBruce Evans 	if (__builtin_constant_p(port) && ((port) & 0xffff) < 0x100	\
162388dfa71SBruce Evans 	    && (port) < 0x10000)					\
163004bedebSBruce Evans 		_data = inbc(port);					\
164004bedebSBruce Evans 	else								\
165004bedebSBruce Evans 		_data = inbv(port);					\
166004bedebSBruce Evans 	_data; })
167004bedebSBruce Evans 
168388dfa71SBruce Evans #define	outb(port, data) (						\
169388dfa71SBruce Evans 	__builtin_constant_p(port) && ((port) & 0xffff) < 0x100		\
170388dfa71SBruce Evans 	&& (port) < 0x10000						\
171004bedebSBruce Evans 	? outbc(port, data) : outbv(port, data))
172004bedebSBruce Evans 
173004bedebSBruce Evans static __inline u_char
174004bedebSBruce Evans inbc(u_int port)
175004bedebSBruce Evans {
176004bedebSBruce Evans 	u_char	data;
177004bedebSBruce Evans 
1788089a043SBruce Evans 	__asm __volatile("inb %1,%0" : "=a" (data) : "id" ((u_short)(port)));
179004bedebSBruce Evans 	return (data);
180004bedebSBruce Evans }
181004bedebSBruce Evans 
182004bedebSBruce Evans static __inline void
183004bedebSBruce Evans outbc(u_int port, u_char data)
184004bedebSBruce Evans {
1858089a043SBruce Evans 	__asm __volatile("outb %0,%1" : : "a" (data), "id" ((u_short)(port)));
186004bedebSBruce Evans }
187004bedebSBruce Evans 
188004bedebSBruce Evans #endif /* __GNUC <= 2 */
189004bedebSBruce Evans 
190004bedebSBruce Evans static __inline u_char
191004bedebSBruce Evans inbv(u_int port)
192004bedebSBruce Evans {
193004bedebSBruce Evans 	u_char	data;
194004bedebSBruce Evans 	/*
195004bedebSBruce Evans 	 * We use %%dx and not %1 here because i/o is done at %dx and not at
196004bedebSBruce Evans 	 * %edx, while gcc generates inferior code (movw instead of movl)
197004bedebSBruce Evans 	 * if we tell it to load (u_short) port.
198004bedebSBruce Evans 	 */
199004bedebSBruce Evans 	__asm __volatile("inb %%dx,%0" : "=a" (data) : "d" (port));
200004bedebSBruce Evans 	return (data);
201004bedebSBruce Evans }
202004bedebSBruce Evans 
20300be8601SBruce Evans static __inline u_int
204004bedebSBruce Evans inl(u_int port)
205004bedebSBruce Evans {
20600be8601SBruce Evans 	u_int	data;
207004bedebSBruce Evans 
208004bedebSBruce Evans 	__asm __volatile("inl %%dx,%0" : "=a" (data) : "d" (port));
209004bedebSBruce Evans 	return (data);
210004bedebSBruce Evans }
211004bedebSBruce Evans 
212004bedebSBruce Evans static __inline void
213004bedebSBruce Evans insb(u_int port, void *addr, size_t cnt)
214004bedebSBruce Evans {
215004bedebSBruce Evans 	__asm __volatile("cld; rep; insb"
2163f9a462fSJohn Baldwin 			 : "+D" (addr), "+c" (cnt)
2173f9a462fSJohn Baldwin 			 : "d" (port)
218896763faSBruce Evans 			 : "memory");
219004bedebSBruce Evans }
220004bedebSBruce Evans 
221004bedebSBruce Evans static __inline void
222004bedebSBruce Evans insw(u_int port, void *addr, size_t cnt)
223004bedebSBruce Evans {
224004bedebSBruce Evans 	__asm __volatile("cld; rep; insw"
2253f9a462fSJohn Baldwin 			 : "+D" (addr), "+c" (cnt)
2263f9a462fSJohn Baldwin 			 : "d" (port)
227896763faSBruce Evans 			 : "memory");
228004bedebSBruce Evans }
229004bedebSBruce Evans 
230004bedebSBruce Evans static __inline void
231004bedebSBruce Evans insl(u_int port, void *addr, size_t cnt)
232004bedebSBruce Evans {
233004bedebSBruce Evans 	__asm __volatile("cld; rep; insl"
2343f9a462fSJohn Baldwin 			 : "+D" (addr), "+c" (cnt)
2353f9a462fSJohn Baldwin 			 : "d" (port)
236896763faSBruce Evans 			 : "memory");
237004bedebSBruce Evans }
238004bedebSBruce Evans 
239ece15d78SBruce Evans static __inline void
2404c024bbdSKATO Takenori invd(void)
2414c024bbdSKATO Takenori {
2424c024bbdSKATO Takenori 	__asm __volatile("invd");
2434c024bbdSKATO Takenori }
2444c024bbdSKATO Takenori 
245004bedebSBruce Evans static __inline u_short
246004bedebSBruce Evans inw(u_int port)
247004bedebSBruce Evans {
248004bedebSBruce Evans 	u_short	data;
249004bedebSBruce Evans 
250004bedebSBruce Evans 	__asm __volatile("inw %%dx,%0" : "=a" (data) : "d" (port));
251004bedebSBruce Evans 	return (data);
252004bedebSBruce Evans }
253004bedebSBruce Evans 
254004bedebSBruce Evans static __inline void
255004bedebSBruce Evans outbv(u_int port, u_char data)
256004bedebSBruce Evans {
257004bedebSBruce Evans 	u_char	al;
258004bedebSBruce Evans 	/*
259004bedebSBruce Evans 	 * Use an unnecessary assignment to help gcc's register allocator.
260004bedebSBruce Evans 	 * This make a large difference for gcc-1.40 and a tiny difference
261004bedebSBruce Evans 	 * for gcc-2.6.0.  For gcc-1.40, al had to be ``asm("ax")'' for
262004bedebSBruce Evans 	 * best results.  gcc-2.6.0 can't handle this.
263004bedebSBruce Evans 	 */
264004bedebSBruce Evans 	al = data;
265004bedebSBruce Evans 	__asm __volatile("outb %0,%%dx" : : "a" (al), "d" (port));
266004bedebSBruce Evans }
267004bedebSBruce Evans 
268004bedebSBruce Evans static __inline void
26900be8601SBruce Evans outl(u_int port, u_int data)
270004bedebSBruce Evans {
271004bedebSBruce Evans 	/*
272004bedebSBruce Evans 	 * outl() and outw() aren't used much so we haven't looked at
273004bedebSBruce Evans 	 * possible micro-optimizations such as the unnecessary
274004bedebSBruce Evans 	 * assignment for them.
275004bedebSBruce Evans 	 */
276004bedebSBruce Evans 	__asm __volatile("outl %0,%%dx" : : "a" (data), "d" (port));
277004bedebSBruce Evans }
278004bedebSBruce Evans 
279004bedebSBruce Evans static __inline void
280e1a1bba4SJustin T. Gibbs outsb(u_int port, const void *addr, size_t cnt)
281004bedebSBruce Evans {
282004bedebSBruce Evans 	__asm __volatile("cld; rep; outsb"
2833f9a462fSJohn Baldwin 			 : "+S" (addr), "+c" (cnt)
2843f9a462fSJohn Baldwin 			 : "d" (port));
285004bedebSBruce Evans }
286004bedebSBruce Evans 
287004bedebSBruce Evans static __inline void
288e1a1bba4SJustin T. Gibbs outsw(u_int port, const void *addr, size_t cnt)
289004bedebSBruce Evans {
290004bedebSBruce Evans 	__asm __volatile("cld; rep; outsw"
2913f9a462fSJohn Baldwin 			 : "+S" (addr), "+c" (cnt)
2923f9a462fSJohn Baldwin 			 : "d" (port));
293004bedebSBruce Evans }
294004bedebSBruce Evans 
295004bedebSBruce Evans static __inline void
296e1a1bba4SJustin T. Gibbs outsl(u_int port, const void *addr, size_t cnt)
297004bedebSBruce Evans {
298004bedebSBruce Evans 	__asm __volatile("cld; rep; outsl"
2993f9a462fSJohn Baldwin 			 : "+S" (addr), "+c" (cnt)
3003f9a462fSJohn Baldwin 			 : "d" (port));
301004bedebSBruce Evans }
302004bedebSBruce Evans 
303004bedebSBruce Evans static __inline void
304004bedebSBruce Evans outw(u_int port, u_short data)
305004bedebSBruce Evans {
306004bedebSBruce Evans 	__asm __volatile("outw %0,%%dx" : : "a" (data), "d" (port));
307004bedebSBruce Evans }
308004bedebSBruce Evans 
3092be69f32SJohn Baldwin static __inline void
3106b8c6989SJohn Baldwin ia32_pause(void)
3112be69f32SJohn Baldwin {
3122be69f32SJohn Baldwin 	__asm __volatile("pause");
3132be69f32SJohn Baldwin }
3142be69f32SJohn Baldwin 
315afa88623SPeter Wemm static __inline u_long
316afa88623SPeter Wemm read_rflags(void)
3175b81b6b3SRodney W. Grimes {
318afa88623SPeter Wemm 	u_long	rf;
319004bedebSBruce Evans 
320afa88623SPeter Wemm 	__asm __volatile("pushfq; popq %0" : "=r" (rf));
321afa88623SPeter Wemm 	return (rf);
3225b81b6b3SRodney W. Grimes }
3235b81b6b3SRodney W. Grimes 
32400be8601SBruce Evans static __inline u_int64_t
3255dbd168eSBruce Evans rdmsr(u_int msr)
3265dbd168eSBruce Evans {
327afa88623SPeter Wemm 	u_int32_t low, high;
3285dbd168eSBruce Evans 
329afa88623SPeter Wemm 	__asm __volatile("rdmsr" : "=a" (low), "=d" (high) : "c" (msr));
330afa88623SPeter Wemm 	return (low | ((u_int64_t)high << 32));
3315dbd168eSBruce Evans }
3325dbd168eSBruce Evans 
33300be8601SBruce Evans static __inline u_int64_t
3345dbd168eSBruce Evans rdpmc(u_int pmc)
3355dbd168eSBruce Evans {
336afa88623SPeter Wemm 	u_int32_t low, high;
3375dbd168eSBruce Evans 
338afa88623SPeter Wemm 	__asm __volatile("rdpmc" : "=a" (low), "=d" (high) : "c" (pmc));
339afa88623SPeter Wemm 	return (low | ((u_int64_t)high << 32));
3405dbd168eSBruce Evans }
3415dbd168eSBruce Evans 
34200be8601SBruce Evans static __inline u_int64_t
3435dbd168eSBruce Evans rdtsc(void)
3445dbd168eSBruce Evans {
345afa88623SPeter Wemm 	u_int32_t low, high;
3465dbd168eSBruce Evans 
347afa88623SPeter Wemm 	__asm __volatile("rdtsc" : "=a" (low), "=d" (high));
348afa88623SPeter Wemm 	return (low | ((u_int64_t)high << 32));
3495dbd168eSBruce Evans }
3505dbd168eSBruce Evans 
351004bedebSBruce Evans static __inline void
3524c024bbdSKATO Takenori wbinvd(void)
3534c024bbdSKATO Takenori {
3544c024bbdSKATO Takenori 	__asm __volatile("wbinvd");
3554c024bbdSKATO Takenori }
3564c024bbdSKATO Takenori 
3574c024bbdSKATO Takenori static __inline void
358afa88623SPeter Wemm write_rflags(u_long rf)
3595b81b6b3SRodney W. Grimes {
360afa88623SPeter Wemm 	__asm __volatile("pushq %0;  popfq" : : "r" (rf));
3615b81b6b3SRodney W. Grimes }
3625b81b6b3SRodney W. Grimes 
363d69e8502SGarrett Wollman static __inline void
36400be8601SBruce Evans wrmsr(u_int msr, u_int64_t newval)
365d69e8502SGarrett Wollman {
366afa88623SPeter Wemm 	u_int32_t low, high;
367afa88623SPeter Wemm 
368afa88623SPeter Wemm 	low = newval;
369afa88623SPeter Wemm 	high = newval >> 32;
370afa88623SPeter Wemm 	__asm __volatile("wrmsr" : : "a" (low), "d" (high), "c" (msr));
371d69e8502SGarrett Wollman }
372d69e8502SGarrett Wollman 
373f1b665c8SPeter Wemm static __inline void
374afa88623SPeter Wemm load_cr0(u_long data)
375f1b665c8SPeter Wemm {
376f1b665c8SPeter Wemm 
377afa88623SPeter Wemm 	__asm __volatile("movq %0,%%cr0" : : "r" (data));
378f1b665c8SPeter Wemm }
379f1b665c8SPeter Wemm 
380afa88623SPeter Wemm static __inline u_long
381f1b665c8SPeter Wemm rcr0(void)
382f1b665c8SPeter Wemm {
383afa88623SPeter Wemm 	u_long	data;
384f1b665c8SPeter Wemm 
385afa88623SPeter Wemm 	__asm __volatile("movq %%cr0,%0" : "=r" (data));
386f1b665c8SPeter Wemm 	return (data);
387f1b665c8SPeter Wemm }
388f1b665c8SPeter Wemm 
389afa88623SPeter Wemm static __inline u_long
390f1b665c8SPeter Wemm rcr2(void)
391f1b665c8SPeter Wemm {
392afa88623SPeter Wemm 	u_long	data;
393f1b665c8SPeter Wemm 
394afa88623SPeter Wemm 	__asm __volatile("movq %%cr2,%0" : "=r" (data));
395f1b665c8SPeter Wemm 	return (data);
396f1b665c8SPeter Wemm }
397f1b665c8SPeter Wemm 
398f1b665c8SPeter Wemm static __inline void
399afa88623SPeter Wemm load_cr3(u_long data)
400f1b665c8SPeter Wemm {
401f1b665c8SPeter Wemm 
402afa88623SPeter Wemm 	__asm __volatile("movq %0,%%cr3" : : "r" (data) : "memory");
403f1b665c8SPeter Wemm }
404f1b665c8SPeter Wemm 
405afa88623SPeter Wemm static __inline u_long
406f1b665c8SPeter Wemm rcr3(void)
407f1b665c8SPeter Wemm {
408afa88623SPeter Wemm 	u_long	data;
409f1b665c8SPeter Wemm 
410afa88623SPeter Wemm 	__asm __volatile("movq %%cr3,%0" : "=r" (data));
411f1b665c8SPeter Wemm 	return (data);
412f1b665c8SPeter Wemm }
413f1b665c8SPeter Wemm 
414f1b665c8SPeter Wemm static __inline void
415afa88623SPeter Wemm load_cr4(u_long data)
416f1b665c8SPeter Wemm {
417afa88623SPeter Wemm 	__asm __volatile("movq %0,%%cr4" : : "r" (data));
418f1b665c8SPeter Wemm }
419f1b665c8SPeter Wemm 
420afa88623SPeter Wemm static __inline u_long
421f1b665c8SPeter Wemm rcr4(void)
422f1b665c8SPeter Wemm {
423afa88623SPeter Wemm 	u_long	data;
424f1b665c8SPeter Wemm 
425afa88623SPeter Wemm 	__asm __volatile("movq %%cr4,%0" : "=r" (data));
426f1b665c8SPeter Wemm 	return (data);
427f1b665c8SPeter Wemm }
428f1b665c8SPeter Wemm 
429f1b665c8SPeter Wemm /*
430f1b665c8SPeter Wemm  * Global TLB flush (except for thise for pages marked PG_G)
431f1b665c8SPeter Wemm  */
432f1b665c8SPeter Wemm static __inline void
433f1b665c8SPeter Wemm invltlb(void)
434f1b665c8SPeter Wemm {
435f1b665c8SPeter Wemm 
436f1b665c8SPeter Wemm 	load_cr3(rcr3());
437f1b665c8SPeter Wemm }
438f1b665c8SPeter Wemm 
439f1b665c8SPeter Wemm /*
440f1b665c8SPeter Wemm  * TLB flush for an individual page (even if it has PG_G).
441f1b665c8SPeter Wemm  * Only works on 486+ CPUs (i386 does not have PG_G).
442f1b665c8SPeter Wemm  */
443f1b665c8SPeter Wemm static __inline void
444afa88623SPeter Wemm invlpg(u_long addr)
445f1b665c8SPeter Wemm {
446f1b665c8SPeter Wemm 
447f1b665c8SPeter Wemm 	__asm __volatile("invlpg %0" : : "m" (*(char *)addr) : "memory");
448f1b665c8SPeter Wemm }
449f1b665c8SPeter Wemm 
4505206bca1SLuoqi Chen static __inline u_int
4515206bca1SLuoqi Chen rfs(void)
4525206bca1SLuoqi Chen {
453d1fc2022SDavid Xu 	u_int sel;
454d1fc2022SDavid Xu 	__asm __volatile("movl %%fs,%0" : "=rm" (sel));
4555206bca1SLuoqi Chen 	return (sel);
4565206bca1SLuoqi Chen }
4575206bca1SLuoqi Chen 
4585206bca1SLuoqi Chen static __inline u_int
4595206bca1SLuoqi Chen rgs(void)
4605206bca1SLuoqi Chen {
461d1fc2022SDavid Xu 	u_int sel;
462d1fc2022SDavid Xu 	__asm __volatile("movl %%gs,%0" : "=rm" (sel));
4635206bca1SLuoqi Chen 	return (sel);
4645206bca1SLuoqi Chen }
4655206bca1SLuoqi Chen 
4665206bca1SLuoqi Chen static __inline void
467d85631c4SPeter Wemm load_ds(u_int sel)
468d85631c4SPeter Wemm {
469d85631c4SPeter Wemm 	__asm __volatile("movl %0,%%ds" : : "rm" (sel));
470d85631c4SPeter Wemm }
471d85631c4SPeter Wemm 
472d85631c4SPeter Wemm static __inline void
473d85631c4SPeter Wemm load_es(u_int sel)
474d85631c4SPeter Wemm {
475d85631c4SPeter Wemm 	__asm __volatile("movl %0,%%es" : : "rm" (sel));
476d85631c4SPeter Wemm }
477d85631c4SPeter Wemm 
478d85631c4SPeter Wemm static __inline void
4795206bca1SLuoqi Chen load_fs(u_int sel)
4805206bca1SLuoqi Chen {
481e870e9b2SLuoqi Chen 	__asm __volatile("movl %0,%%fs" : : "rm" (sel));
4825206bca1SLuoqi Chen }
4835206bca1SLuoqi Chen 
4845206bca1SLuoqi Chen static __inline void
4855206bca1SLuoqi Chen load_gs(u_int sel)
4865206bca1SLuoqi Chen {
487e870e9b2SLuoqi Chen 	__asm __volatile("movl %0,%%gs" : : "rm" (sel));
4885206bca1SLuoqi Chen }
4895206bca1SLuoqi Chen 
490eb1443c8SPeter Wemm /* void lidt(struct region_descriptor *addr); */
491eb1443c8SPeter Wemm static __inline void
492eb1443c8SPeter Wemm lidt(struct region_descriptor *addr)
493eb1443c8SPeter Wemm {
494eb1443c8SPeter Wemm 	__asm __volatile("lidt (%0)" : : "r" (addr));
495eb1443c8SPeter Wemm }
496eb1443c8SPeter Wemm 
497eb1443c8SPeter Wemm /* void lldt(u_short sel); */
498eb1443c8SPeter Wemm static __inline void
499eb1443c8SPeter Wemm lldt(u_short sel)
500eb1443c8SPeter Wemm {
501eb1443c8SPeter Wemm 	__asm __volatile("lldt %0" : : "r" (sel));
502eb1443c8SPeter Wemm }
503eb1443c8SPeter Wemm 
504eb1443c8SPeter Wemm /* void ltr(u_short sel); */
505eb1443c8SPeter Wemm static __inline void
506eb1443c8SPeter Wemm ltr(u_short sel)
507eb1443c8SPeter Wemm {
508eb1443c8SPeter Wemm 	__asm __volatile("ltr %0" : : "r" (sel));
509eb1443c8SPeter Wemm }
510eb1443c8SPeter Wemm 
511ba74981eSWarner Losh static __inline register_t
512ba74981eSWarner Losh intr_disable(void)
513ba74981eSWarner Losh {
514afa88623SPeter Wemm 	register_t rflags;
515ba74981eSWarner Losh 
516afa88623SPeter Wemm 	rflags = read_rflags();
517ba74981eSWarner Losh 	disable_intr();
518afa88623SPeter Wemm 	return (rflags);
519ba74981eSWarner Losh }
520ba74981eSWarner Losh 
521ba74981eSWarner Losh static __inline void
522afa88623SPeter Wemm intr_restore(register_t rflags)
523ba74981eSWarner Losh {
524afa88623SPeter Wemm 	write_rflags(rflags);
525ba74981eSWarner Losh }
526ba74981eSWarner Losh 
527004bedebSBruce Evans #else /* !__GNUC__ */
5285b81b6b3SRodney W. Grimes 
529b63dc6adSAlfred Perlstein int	breakpoint(void);
530b63dc6adSAlfred Perlstein u_int	bsfl(u_int mask);
531b63dc6adSAlfred Perlstein u_int	bsrl(u_int mask);
532afa88623SPeter Wemm void	cpu_invlpg(u_long addr);
533afa88623SPeter Wemm void	cpu_invlpg_range(u_long start, u_long end);
534b63dc6adSAlfred Perlstein void	disable_intr(void);
535b63dc6adSAlfred Perlstein void	do_cpuid(u_int ax, u_int *p);
536b63dc6adSAlfred Perlstein void	enable_intr(void);
537d7ee4425SMark Murray void	halt(void);
538b63dc6adSAlfred Perlstein u_char	inb(u_int port);
539b63dc6adSAlfred Perlstein u_int	inl(u_int port);
540b63dc6adSAlfred Perlstein void	insb(u_int port, void *addr, size_t cnt);
541b63dc6adSAlfred Perlstein void	insl(u_int port, void *addr, size_t cnt);
542b63dc6adSAlfred Perlstein void	insw(u_int port, void *addr, size_t cnt);
543b63dc6adSAlfred Perlstein void	invd(void);
544b63dc6adSAlfred Perlstein void	invlpg(u_int addr);
545f1b665c8SPeter Wemm void	invlpg_range(u_int start, u_int end);
546b63dc6adSAlfred Perlstein void	invltlb(void);
547b63dc6adSAlfred Perlstein u_short	inw(u_int port);
548f1b665c8SPeter Wemm void	load_cr0(u_int cr0);
549f1b665c8SPeter Wemm void	load_cr3(u_int cr3);
550f1b665c8SPeter Wemm void	load_cr4(u_int cr4);
551f1b665c8SPeter Wemm void	load_fs(u_int sel);
552f1b665c8SPeter Wemm void	load_gs(u_int sel);
553eb1443c8SPeter Wemm struct region_descriptor;
554eb1443c8SPeter Wemm void	lidt(struct region_descriptor *addr);
555eb1443c8SPeter Wemm void	lldt(u_short sel);
556eb1443c8SPeter Wemm void	ltr(u_short sel);
557b63dc6adSAlfred Perlstein void	outb(u_int port, u_char data);
558b63dc6adSAlfred Perlstein void	outl(u_int port, u_int data);
559b63dc6adSAlfred Perlstein void	outsb(u_int port, void *addr, size_t cnt);
560b63dc6adSAlfred Perlstein void	outsl(u_int port, void *addr, size_t cnt);
561b63dc6adSAlfred Perlstein void	outsw(u_int port, void *addr, size_t cnt);
562b63dc6adSAlfred Perlstein void	outw(u_int port, u_short data);
5636b8c6989SJohn Baldwin void	ia32_pause(void);
564f1b665c8SPeter Wemm u_int	rcr0(void);
565b63dc6adSAlfred Perlstein u_int	rcr2(void);
566f1b665c8SPeter Wemm u_int	rcr3(void);
567f1b665c8SPeter Wemm u_int	rcr4(void);
568f1b665c8SPeter Wemm u_int	rfs(void);
569f1b665c8SPeter Wemm u_int	rgs(void);
570b63dc6adSAlfred Perlstein u_int64_t rdmsr(u_int msr);
571b63dc6adSAlfred Perlstein u_int64_t rdpmc(u_int pmc);
572b63dc6adSAlfred Perlstein u_int64_t rdtsc(void);
573afa88623SPeter Wemm u_int	read_rflags(void);
574b63dc6adSAlfred Perlstein void	wbinvd(void);
575afa88623SPeter Wemm void	write_rflags(u_int rf);
576b63dc6adSAlfred Perlstein void	wrmsr(u_int msr, u_int64_t newval);
57707508f90SJohn Baldwin void	load_dr7(u_int dr7);
5782be69f32SJohn Baldwin register_t	intr_disable(void);
579afa88623SPeter Wemm void	intr_restore(register_t rf);
580004bedebSBruce Evans 
5815b81b6b3SRodney W. Grimes #endif	/* __GNUC__ */
5825b81b6b3SRodney W. Grimes 
583b63dc6adSAlfred Perlstein void    reset_dbregs(void);
584d74ac681SMatthew Dillon 
58529d5de8aSWarner Losh __END_DECLS
5865b81b6b3SRodney W. Grimes 
587004bedebSBruce Evans #endif /* !_MACHINE_CPUFUNC_H_ */
588