xref: /freebsd/sys/amd64/include/cpufunc.h (revision fcfe57d64080fe861c8dc9d41bc675338ff4ad9a)
13c4dd356SDavid Greenman /*-
2fcfe57d6SPeter Wemm  * Copyright (c) 2003 Peter Wemm.
33c4dd356SDavid Greenman  * Copyright (c) 1993 The Regents of the University of California.
43c4dd356SDavid Greenman  * All rights reserved.
53c4dd356SDavid Greenman  *
63c4dd356SDavid Greenman  * Redistribution and use in source and binary forms, with or without
73c4dd356SDavid Greenman  * modification, are permitted provided that the following conditions
83c4dd356SDavid Greenman  * are met:
93c4dd356SDavid Greenman  * 1. Redistributions of source code must retain the above copyright
103c4dd356SDavid Greenman  *    notice, this list of conditions and the following disclaimer.
113c4dd356SDavid Greenman  * 2. Redistributions in binary form must reproduce the above copyright
123c4dd356SDavid Greenman  *    notice, this list of conditions and the following disclaimer in the
133c4dd356SDavid Greenman  *    documentation and/or other materials provided with the distribution.
143c4dd356SDavid Greenman  * 3. All advertising materials mentioning features or use of this software
153c4dd356SDavid Greenman  *    must display the following acknowledgement:
163c4dd356SDavid Greenman  *	This product includes software developed by the University of
173c4dd356SDavid Greenman  *	California, Berkeley and its contributors.
183c4dd356SDavid Greenman  * 4. Neither the name of the University nor the names of its contributors
193c4dd356SDavid Greenman  *    may be used to endorse or promote products derived from this software
203c4dd356SDavid Greenman  *    without specific prior written permission.
213c4dd356SDavid Greenman  *
223c4dd356SDavid Greenman  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
233c4dd356SDavid Greenman  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
243c4dd356SDavid Greenman  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
253c4dd356SDavid Greenman  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
263c4dd356SDavid Greenman  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
273c4dd356SDavid Greenman  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
283c4dd356SDavid Greenman  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
293c4dd356SDavid Greenman  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
303c4dd356SDavid Greenman  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
313c4dd356SDavid Greenman  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
323c4dd356SDavid Greenman  * SUCH DAMAGE.
333c4dd356SDavid Greenman  *
34c3aac50fSPeter Wemm  * $FreeBSD$
353c4dd356SDavid Greenman  */
363c4dd356SDavid Greenman 
375b81b6b3SRodney W. Grimes /*
385b81b6b3SRodney W. Grimes  * Functions to provide access to special i386 instructions.
39f5d9a10bSMark Murray  * This in included in sys/systm.h, and that file should be
40f5d9a10bSMark Murray  * used in preference to this.
415b81b6b3SRodney W. Grimes  */
425b81b6b3SRodney W. Grimes 
436e393973SGarrett Wollman #ifndef _MACHINE_CPUFUNC_H_
44004bedebSBruce Evans #define	_MACHINE_CPUFUNC_H_
456e393973SGarrett Wollman 
4629d5de8aSWarner Losh #include <sys/cdefs.h>
477e1f6dfeSJohn Baldwin #include <machine/psl.h>
4829d5de8aSWarner Losh 
49d74ac681SMatthew Dillon struct thread;
50eb1443c8SPeter Wemm struct region_descriptor;
51d74ac681SMatthew Dillon 
5229d5de8aSWarner Losh __BEGIN_DECLS
53e31fa854SDoug Rabson #define readb(va)	(*(volatile u_int8_t *) (va))
54e31fa854SDoug Rabson #define readw(va)	(*(volatile u_int16_t *) (va))
55e31fa854SDoug Rabson #define readl(va)	(*(volatile u_int32_t *) (va))
56afa88623SPeter Wemm #define readq(va)	(*(volatile u_int64_t *) (va))
57e31fa854SDoug Rabson 
58e31fa854SDoug Rabson #define writeb(va, d)	(*(volatile u_int8_t *) (va) = (d))
59e31fa854SDoug Rabson #define writew(va, d)	(*(volatile u_int16_t *) (va) = (d))
60e31fa854SDoug Rabson #define writel(va, d)	(*(volatile u_int32_t *) (va) = (d))
61afa88623SPeter Wemm #define writeq(va, d)	(*(volatile u_int64_t *) (va) = (d))
62e31fa854SDoug Rabson 
635b81b6b3SRodney W. Grimes #ifdef	__GNUC__
645b81b6b3SRodney W. Grimes 
655dbd168eSBruce Evans static __inline void
665dbd168eSBruce Evans breakpoint(void)
67004bedebSBruce Evans {
68004bedebSBruce Evans 	__asm __volatile("int $3");
695b81b6b3SRodney W. Grimes }
705b81b6b3SRodney W. Grimes 
71c83b1328SBruce Evans static __inline u_int
72c83b1328SBruce Evans bsfl(u_int mask)
73c83b1328SBruce Evans {
74c83b1328SBruce Evans 	u_int	result;
75c83b1328SBruce Evans 
763f9a462fSJohn Baldwin 	__asm __volatile("bsfl %1,%0" : "=r" (result) : "rm" (mask));
77c83b1328SBruce Evans 	return (result);
78c83b1328SBruce Evans }
79c83b1328SBruce Evans 
80c83b1328SBruce Evans static __inline u_int
81c83b1328SBruce Evans bsrl(u_int mask)
82c83b1328SBruce Evans {
83c83b1328SBruce Evans 	u_int	result;
84c83b1328SBruce Evans 
853f9a462fSJohn Baldwin 	__asm __volatile("bsrl %1,%0" : "=r" (result) : "rm" (mask));
86c83b1328SBruce Evans 	return (result);
87c83b1328SBruce Evans }
88c83b1328SBruce Evans 
89004bedebSBruce Evans static __inline void
905b81b6b3SRodney W. Grimes disable_intr(void)
915b81b6b3SRodney W. Grimes {
928966b85cSJohn Dyson 	__asm __volatile("cli" : : : "memory");
935b81b6b3SRodney W. Grimes }
945b81b6b3SRodney W. Grimes 
95004bedebSBruce Evans static __inline void
96a983fdfeSDavid Malone do_cpuid(u_int ax, u_int *p)
97a983fdfeSDavid Malone {
98a983fdfeSDavid Malone 	__asm __volatile("cpuid"
99a983fdfeSDavid Malone 			 : "=a" (p[0]), "=b" (p[1]), "=c" (p[2]), "=d" (p[3])
100a983fdfeSDavid Malone 			 :  "0" (ax));
101a983fdfeSDavid Malone }
102a983fdfeSDavid Malone 
103a983fdfeSDavid Malone static __inline void
1045b81b6b3SRodney W. Grimes enable_intr(void)
1055b81b6b3SRodney W. Grimes {
106fadc51bdSBruce Evans 	__asm __volatile("sti");
1075b81b6b3SRodney W. Grimes }
1085b81b6b3SRodney W. Grimes 
109264c3d87SPeter Wemm #define	HAVE_INLINE_FFS
110264c3d87SPeter Wemm 
111264c3d87SPeter Wemm static __inline int
112264c3d87SPeter Wemm ffs(int mask)
113264c3d87SPeter Wemm {
114264c3d87SPeter Wemm 	/*
115004bedebSBruce Evans 	 * Note that gcc-2's builtin ffs would be used if we didn't declare
116004bedebSBruce Evans 	 * this inline or turn off the builtin.  The builtin is faster but
117c83b1328SBruce Evans 	 * broken in gcc-2.4.5 and slower but working in gcc-2.5 and later
118c83b1328SBruce Evans 	 * versions.
119004bedebSBruce Evans 	 */
1207e622d3cSMark Murray 	 return (mask == 0 ? mask : (int)bsfl((u_int)mask) + 1);
121004bedebSBruce Evans }
122004bedebSBruce Evans 
12313f588f8SGarrett Wollman #define	HAVE_INLINE_FLS
12413f588f8SGarrett Wollman 
12513f588f8SGarrett Wollman static __inline int
12613f588f8SGarrett Wollman fls(int mask)
12713f588f8SGarrett Wollman {
1287e622d3cSMark Murray 	return (mask == 0 ? mask : (int)bsrl((u_int)mask) + 1);
12913f588f8SGarrett Wollman }
13013f588f8SGarrett Wollman 
131d7ee4425SMark Murray static __inline void
132d7ee4425SMark Murray halt(void)
133d7ee4425SMark Murray {
134d7ee4425SMark Murray 	__asm __volatile("hlt");
135d7ee4425SMark Murray }
136d7ee4425SMark Murray 
137004bedebSBruce Evans #if __GNUC__ < 2
138004bedebSBruce Evans 
139004bedebSBruce Evans #define	inb(port)		inbv(port)
140004bedebSBruce Evans #define	outb(port, data)	outbv(port, data)
141004bedebSBruce Evans 
142004bedebSBruce Evans #else /* __GNUC >= 2 */
143004bedebSBruce Evans 
144004bedebSBruce Evans /*
1458089a043SBruce Evans  * The following complications are to get around gcc not having a
1468089a043SBruce Evans  * constraint letter for the range 0..255.  We still put "d" in the
1478089a043SBruce Evans  * constraint because "i" isn't a valid constraint when the port
1488089a043SBruce Evans  * isn't constant.  This only matters for -O0 because otherwise
1498089a043SBruce Evans  * the non-working version gets optimized away.
1508089a043SBruce Evans  *
151004bedebSBruce Evans  * Use an expression-statement instead of a conditional expression
152004bedebSBruce Evans  * because gcc-2.6.0 would promote the operands of the conditional
153004bedebSBruce Evans  * and produce poor code for "if ((inb(var) & const1) == const2)".
154388dfa71SBruce Evans  *
155388dfa71SBruce Evans  * The unnecessary test `(port) < 0x10000' is to generate a warning if
156388dfa71SBruce Evans  * the `port' has type u_short or smaller.  Such types are pessimal.
157388dfa71SBruce Evans  * This actually only works for signed types.  The range check is
158388dfa71SBruce Evans  * careful to avoid generating warnings.
159004bedebSBruce Evans  */
160388dfa71SBruce Evans #define	inb(port) __extension__ ({					\
161004bedebSBruce Evans 	u_char	_data;							\
162388dfa71SBruce Evans 	if (__builtin_constant_p(port) && ((port) & 0xffff) < 0x100	\
163388dfa71SBruce Evans 	    && (port) < 0x10000)					\
164004bedebSBruce Evans 		_data = inbc(port);					\
165004bedebSBruce Evans 	else								\
166004bedebSBruce Evans 		_data = inbv(port);					\
167004bedebSBruce Evans 	_data; })
168004bedebSBruce Evans 
169388dfa71SBruce Evans #define	outb(port, data) (						\
170388dfa71SBruce Evans 	__builtin_constant_p(port) && ((port) & 0xffff) < 0x100		\
171388dfa71SBruce Evans 	&& (port) < 0x10000						\
172004bedebSBruce Evans 	? outbc(port, data) : outbv(port, data))
173004bedebSBruce Evans 
174004bedebSBruce Evans static __inline u_char
175004bedebSBruce Evans inbc(u_int port)
176004bedebSBruce Evans {
177004bedebSBruce Evans 	u_char	data;
178004bedebSBruce Evans 
1798089a043SBruce Evans 	__asm __volatile("inb %1,%0" : "=a" (data) : "id" ((u_short)(port)));
180004bedebSBruce Evans 	return (data);
181004bedebSBruce Evans }
182004bedebSBruce Evans 
183004bedebSBruce Evans static __inline void
184004bedebSBruce Evans outbc(u_int port, u_char data)
185004bedebSBruce Evans {
1868089a043SBruce Evans 	__asm __volatile("outb %0,%1" : : "a" (data), "id" ((u_short)(port)));
187004bedebSBruce Evans }
188004bedebSBruce Evans 
189004bedebSBruce Evans #endif /* __GNUC <= 2 */
190004bedebSBruce Evans 
191004bedebSBruce Evans static __inline u_char
192004bedebSBruce Evans inbv(u_int port)
193004bedebSBruce Evans {
194004bedebSBruce Evans 	u_char	data;
195004bedebSBruce Evans 	/*
196004bedebSBruce Evans 	 * We use %%dx and not %1 here because i/o is done at %dx and not at
197004bedebSBruce Evans 	 * %edx, while gcc generates inferior code (movw instead of movl)
198004bedebSBruce Evans 	 * if we tell it to load (u_short) port.
199004bedebSBruce Evans 	 */
200004bedebSBruce Evans 	__asm __volatile("inb %%dx,%0" : "=a" (data) : "d" (port));
201004bedebSBruce Evans 	return (data);
202004bedebSBruce Evans }
203004bedebSBruce Evans 
20400be8601SBruce Evans static __inline u_int
205004bedebSBruce Evans inl(u_int port)
206004bedebSBruce Evans {
20700be8601SBruce Evans 	u_int	data;
208004bedebSBruce Evans 
209004bedebSBruce Evans 	__asm __volatile("inl %%dx,%0" : "=a" (data) : "d" (port));
210004bedebSBruce Evans 	return (data);
211004bedebSBruce Evans }
212004bedebSBruce Evans 
213004bedebSBruce Evans static __inline void
214004bedebSBruce Evans insb(u_int port, void *addr, size_t cnt)
215004bedebSBruce Evans {
216004bedebSBruce Evans 	__asm __volatile("cld; rep; insb"
2173f9a462fSJohn Baldwin 			 : "+D" (addr), "+c" (cnt)
2183f9a462fSJohn Baldwin 			 : "d" (port)
219896763faSBruce Evans 			 : "memory");
220004bedebSBruce Evans }
221004bedebSBruce Evans 
222004bedebSBruce Evans static __inline void
223004bedebSBruce Evans insw(u_int port, void *addr, size_t cnt)
224004bedebSBruce Evans {
225004bedebSBruce Evans 	__asm __volatile("cld; rep; insw"
2263f9a462fSJohn Baldwin 			 : "+D" (addr), "+c" (cnt)
2273f9a462fSJohn Baldwin 			 : "d" (port)
228896763faSBruce Evans 			 : "memory");
229004bedebSBruce Evans }
230004bedebSBruce Evans 
231004bedebSBruce Evans static __inline void
232004bedebSBruce Evans insl(u_int port, void *addr, size_t cnt)
233004bedebSBruce Evans {
234004bedebSBruce Evans 	__asm __volatile("cld; rep; insl"
2353f9a462fSJohn Baldwin 			 : "+D" (addr), "+c" (cnt)
2363f9a462fSJohn Baldwin 			 : "d" (port)
237896763faSBruce Evans 			 : "memory");
238004bedebSBruce Evans }
239004bedebSBruce Evans 
240ece15d78SBruce Evans static __inline void
2414c024bbdSKATO Takenori invd(void)
2424c024bbdSKATO Takenori {
2434c024bbdSKATO Takenori 	__asm __volatile("invd");
2444c024bbdSKATO Takenori }
2454c024bbdSKATO Takenori 
246004bedebSBruce Evans static __inline u_short
247004bedebSBruce Evans inw(u_int port)
248004bedebSBruce Evans {
249004bedebSBruce Evans 	u_short	data;
250004bedebSBruce Evans 
251004bedebSBruce Evans 	__asm __volatile("inw %%dx,%0" : "=a" (data) : "d" (port));
252004bedebSBruce Evans 	return (data);
253004bedebSBruce Evans }
254004bedebSBruce Evans 
255004bedebSBruce Evans static __inline void
256004bedebSBruce Evans outbv(u_int port, u_char data)
257004bedebSBruce Evans {
258004bedebSBruce Evans 	u_char	al;
259004bedebSBruce Evans 	/*
260004bedebSBruce Evans 	 * Use an unnecessary assignment to help gcc's register allocator.
261004bedebSBruce Evans 	 * This make a large difference for gcc-1.40 and a tiny difference
262004bedebSBruce Evans 	 * for gcc-2.6.0.  For gcc-1.40, al had to be ``asm("ax")'' for
263004bedebSBruce Evans 	 * best results.  gcc-2.6.0 can't handle this.
264004bedebSBruce Evans 	 */
265004bedebSBruce Evans 	al = data;
266004bedebSBruce Evans 	__asm __volatile("outb %0,%%dx" : : "a" (al), "d" (port));
267004bedebSBruce Evans }
268004bedebSBruce Evans 
269004bedebSBruce Evans static __inline void
27000be8601SBruce Evans outl(u_int port, u_int data)
271004bedebSBruce Evans {
272004bedebSBruce Evans 	/*
273004bedebSBruce Evans 	 * outl() and outw() aren't used much so we haven't looked at
274004bedebSBruce Evans 	 * possible micro-optimizations such as the unnecessary
275004bedebSBruce Evans 	 * assignment for them.
276004bedebSBruce Evans 	 */
277004bedebSBruce Evans 	__asm __volatile("outl %0,%%dx" : : "a" (data), "d" (port));
278004bedebSBruce Evans }
279004bedebSBruce Evans 
280004bedebSBruce Evans static __inline void
281e1a1bba4SJustin T. Gibbs outsb(u_int port, const void *addr, size_t cnt)
282004bedebSBruce Evans {
283004bedebSBruce Evans 	__asm __volatile("cld; rep; outsb"
2843f9a462fSJohn Baldwin 			 : "+S" (addr), "+c" (cnt)
2853f9a462fSJohn Baldwin 			 : "d" (port));
286004bedebSBruce Evans }
287004bedebSBruce Evans 
288004bedebSBruce Evans static __inline void
289e1a1bba4SJustin T. Gibbs outsw(u_int port, const void *addr, size_t cnt)
290004bedebSBruce Evans {
291004bedebSBruce Evans 	__asm __volatile("cld; rep; outsw"
2923f9a462fSJohn Baldwin 			 : "+S" (addr), "+c" (cnt)
2933f9a462fSJohn Baldwin 			 : "d" (port));
294004bedebSBruce Evans }
295004bedebSBruce Evans 
296004bedebSBruce Evans static __inline void
297e1a1bba4SJustin T. Gibbs outsl(u_int port, const void *addr, size_t cnt)
298004bedebSBruce Evans {
299004bedebSBruce Evans 	__asm __volatile("cld; rep; outsl"
3003f9a462fSJohn Baldwin 			 : "+S" (addr), "+c" (cnt)
3013f9a462fSJohn Baldwin 			 : "d" (port));
302004bedebSBruce Evans }
303004bedebSBruce Evans 
304004bedebSBruce Evans static __inline void
305004bedebSBruce Evans outw(u_int port, u_short data)
306004bedebSBruce Evans {
307004bedebSBruce Evans 	__asm __volatile("outw %0,%%dx" : : "a" (data), "d" (port));
308004bedebSBruce Evans }
309004bedebSBruce Evans 
3102be69f32SJohn Baldwin static __inline void
3116b8c6989SJohn Baldwin ia32_pause(void)
3122be69f32SJohn Baldwin {
3132be69f32SJohn Baldwin 	__asm __volatile("pause");
3142be69f32SJohn Baldwin }
3152be69f32SJohn Baldwin 
316afa88623SPeter Wemm static __inline u_long
317afa88623SPeter Wemm read_rflags(void)
3185b81b6b3SRodney W. Grimes {
319afa88623SPeter Wemm 	u_long	rf;
320004bedebSBruce Evans 
321afa88623SPeter Wemm 	__asm __volatile("pushfq; popq %0" : "=r" (rf));
322afa88623SPeter Wemm 	return (rf);
3235b81b6b3SRodney W. Grimes }
3245b81b6b3SRodney W. Grimes 
32500be8601SBruce Evans static __inline u_int64_t
3265dbd168eSBruce Evans rdmsr(u_int msr)
3275dbd168eSBruce Evans {
328afa88623SPeter Wemm 	u_int32_t low, high;
3295dbd168eSBruce Evans 
330afa88623SPeter Wemm 	__asm __volatile("rdmsr" : "=a" (low), "=d" (high) : "c" (msr));
331afa88623SPeter Wemm 	return (low | ((u_int64_t)high << 32));
3325dbd168eSBruce Evans }
3335dbd168eSBruce Evans 
33400be8601SBruce Evans static __inline u_int64_t
3355dbd168eSBruce Evans rdpmc(u_int pmc)
3365dbd168eSBruce Evans {
337afa88623SPeter Wemm 	u_int32_t low, high;
3385dbd168eSBruce Evans 
339afa88623SPeter Wemm 	__asm __volatile("rdpmc" : "=a" (low), "=d" (high) : "c" (pmc));
340afa88623SPeter Wemm 	return (low | ((u_int64_t)high << 32));
3415dbd168eSBruce Evans }
3425dbd168eSBruce Evans 
34300be8601SBruce Evans static __inline u_int64_t
3445dbd168eSBruce Evans rdtsc(void)
3455dbd168eSBruce Evans {
346afa88623SPeter Wemm 	u_int32_t low, high;
3475dbd168eSBruce Evans 
348afa88623SPeter Wemm 	__asm __volatile("rdtsc" : "=a" (low), "=d" (high));
349afa88623SPeter Wemm 	return (low | ((u_int64_t)high << 32));
3505dbd168eSBruce Evans }
3515dbd168eSBruce Evans 
352004bedebSBruce Evans static __inline void
3534c024bbdSKATO Takenori wbinvd(void)
3544c024bbdSKATO Takenori {
3554c024bbdSKATO Takenori 	__asm __volatile("wbinvd");
3564c024bbdSKATO Takenori }
3574c024bbdSKATO Takenori 
3584c024bbdSKATO Takenori static __inline void
359afa88623SPeter Wemm write_rflags(u_long rf)
3605b81b6b3SRodney W. Grimes {
361afa88623SPeter Wemm 	__asm __volatile("pushq %0;  popfq" : : "r" (rf));
3625b81b6b3SRodney W. Grimes }
3635b81b6b3SRodney W. Grimes 
364d69e8502SGarrett Wollman static __inline void
36500be8601SBruce Evans wrmsr(u_int msr, u_int64_t newval)
366d69e8502SGarrett Wollman {
367afa88623SPeter Wemm 	u_int32_t low, high;
368afa88623SPeter Wemm 
369afa88623SPeter Wemm 	low = newval;
370afa88623SPeter Wemm 	high = newval >> 32;
371afa88623SPeter Wemm 	__asm __volatile("wrmsr" : : "a" (low), "d" (high), "c" (msr));
372d69e8502SGarrett Wollman }
373d69e8502SGarrett Wollman 
374f1b665c8SPeter Wemm static __inline void
375afa88623SPeter Wemm load_cr0(u_long data)
376f1b665c8SPeter Wemm {
377f1b665c8SPeter Wemm 
378afa88623SPeter Wemm 	__asm __volatile("movq %0,%%cr0" : : "r" (data));
379f1b665c8SPeter Wemm }
380f1b665c8SPeter Wemm 
381afa88623SPeter Wemm static __inline u_long
382f1b665c8SPeter Wemm rcr0(void)
383f1b665c8SPeter Wemm {
384afa88623SPeter Wemm 	u_long	data;
385f1b665c8SPeter Wemm 
386afa88623SPeter Wemm 	__asm __volatile("movq %%cr0,%0" : "=r" (data));
387f1b665c8SPeter Wemm 	return (data);
388f1b665c8SPeter Wemm }
389f1b665c8SPeter Wemm 
390afa88623SPeter Wemm static __inline u_long
391f1b665c8SPeter Wemm rcr2(void)
392f1b665c8SPeter Wemm {
393afa88623SPeter Wemm 	u_long	data;
394f1b665c8SPeter Wemm 
395afa88623SPeter Wemm 	__asm __volatile("movq %%cr2,%0" : "=r" (data));
396f1b665c8SPeter Wemm 	return (data);
397f1b665c8SPeter Wemm }
398f1b665c8SPeter Wemm 
399f1b665c8SPeter Wemm static __inline void
400afa88623SPeter Wemm load_cr3(u_long data)
401f1b665c8SPeter Wemm {
402f1b665c8SPeter Wemm 
403afa88623SPeter Wemm 	__asm __volatile("movq %0,%%cr3" : : "r" (data) : "memory");
404f1b665c8SPeter Wemm }
405f1b665c8SPeter Wemm 
406afa88623SPeter Wemm static __inline u_long
407f1b665c8SPeter Wemm rcr3(void)
408f1b665c8SPeter Wemm {
409afa88623SPeter Wemm 	u_long	data;
410f1b665c8SPeter Wemm 
411afa88623SPeter Wemm 	__asm __volatile("movq %%cr3,%0" : "=r" (data));
412f1b665c8SPeter Wemm 	return (data);
413f1b665c8SPeter Wemm }
414f1b665c8SPeter Wemm 
415f1b665c8SPeter Wemm static __inline void
416afa88623SPeter Wemm load_cr4(u_long data)
417f1b665c8SPeter Wemm {
418afa88623SPeter Wemm 	__asm __volatile("movq %0,%%cr4" : : "r" (data));
419f1b665c8SPeter Wemm }
420f1b665c8SPeter Wemm 
421afa88623SPeter Wemm static __inline u_long
422f1b665c8SPeter Wemm rcr4(void)
423f1b665c8SPeter Wemm {
424afa88623SPeter Wemm 	u_long	data;
425f1b665c8SPeter Wemm 
426afa88623SPeter Wemm 	__asm __volatile("movq %%cr4,%0" : "=r" (data));
427f1b665c8SPeter Wemm 	return (data);
428f1b665c8SPeter Wemm }
429f1b665c8SPeter Wemm 
430f1b665c8SPeter Wemm /*
431f1b665c8SPeter Wemm  * Global TLB flush (except for thise for pages marked PG_G)
432f1b665c8SPeter Wemm  */
433f1b665c8SPeter Wemm static __inline void
434f1b665c8SPeter Wemm invltlb(void)
435f1b665c8SPeter Wemm {
436f1b665c8SPeter Wemm 
437f1b665c8SPeter Wemm 	load_cr3(rcr3());
438f1b665c8SPeter Wemm }
439f1b665c8SPeter Wemm 
440f1b665c8SPeter Wemm /*
441f1b665c8SPeter Wemm  * TLB flush for an individual page (even if it has PG_G).
442f1b665c8SPeter Wemm  * Only works on 486+ CPUs (i386 does not have PG_G).
443f1b665c8SPeter Wemm  */
444f1b665c8SPeter Wemm static __inline void
445afa88623SPeter Wemm invlpg(u_long addr)
446f1b665c8SPeter Wemm {
447f1b665c8SPeter Wemm 
448f1b665c8SPeter Wemm 	__asm __volatile("invlpg %0" : : "m" (*(char *)addr) : "memory");
449f1b665c8SPeter Wemm }
450f1b665c8SPeter Wemm 
4515206bca1SLuoqi Chen static __inline u_int
4525206bca1SLuoqi Chen rfs(void)
4535206bca1SLuoqi Chen {
454d1fc2022SDavid Xu 	u_int sel;
455d1fc2022SDavid Xu 	__asm __volatile("movl %%fs,%0" : "=rm" (sel));
4565206bca1SLuoqi Chen 	return (sel);
4575206bca1SLuoqi Chen }
4585206bca1SLuoqi Chen 
4595206bca1SLuoqi Chen static __inline u_int
4605206bca1SLuoqi Chen rgs(void)
4615206bca1SLuoqi Chen {
462d1fc2022SDavid Xu 	u_int sel;
463d1fc2022SDavid Xu 	__asm __volatile("movl %%gs,%0" : "=rm" (sel));
4645206bca1SLuoqi Chen 	return (sel);
4655206bca1SLuoqi Chen }
4665206bca1SLuoqi Chen 
4675206bca1SLuoqi Chen static __inline void
468d85631c4SPeter Wemm load_ds(u_int sel)
469d85631c4SPeter Wemm {
470d85631c4SPeter Wemm 	__asm __volatile("movl %0,%%ds" : : "rm" (sel));
471d85631c4SPeter Wemm }
472d85631c4SPeter Wemm 
473d85631c4SPeter Wemm static __inline void
474d85631c4SPeter Wemm load_es(u_int sel)
475d85631c4SPeter Wemm {
476d85631c4SPeter Wemm 	__asm __volatile("movl %0,%%es" : : "rm" (sel));
477d85631c4SPeter Wemm }
478d85631c4SPeter Wemm 
479c0a54ff6SPeter Wemm #ifdef _KERNEL
480c0a54ff6SPeter Wemm /* This is defined in <machine/specialreg.h> but is too painful to get to */
481c0a54ff6SPeter Wemm #ifndef	MSR_FSBASE
482c0a54ff6SPeter Wemm #define	MSR_FSBASE	0xc0000100
483c0a54ff6SPeter Wemm #endif
484c0a54ff6SPeter Wemm static __inline void
485c0a54ff6SPeter Wemm load_fs(u_int sel)
486c0a54ff6SPeter Wemm {
487c0a54ff6SPeter Wemm 	register u_int32_t fsbase __asm("ecx");
488c0a54ff6SPeter Wemm 
489c0a54ff6SPeter Wemm 	/* Preserve the fsbase value across the selector load */
490c0a54ff6SPeter Wemm 	fsbase = MSR_FSBASE;
491c0a54ff6SPeter Wemm         __asm __volatile("rdmsr; movl %0,%%fs; wrmsr"
492c0a54ff6SPeter Wemm             : : "rm" (sel), "c" (fsbase) : "eax", "edx");
493c0a54ff6SPeter Wemm }
494c0a54ff6SPeter Wemm 
495c0a54ff6SPeter Wemm #ifndef	MSR_GSBASE
496c0a54ff6SPeter Wemm #define	MSR_GSBASE	0xc0000101
497c0a54ff6SPeter Wemm #endif
498c0a54ff6SPeter Wemm static __inline void
499c0a54ff6SPeter Wemm load_gs(u_int sel)
500c0a54ff6SPeter Wemm {
501c0a54ff6SPeter Wemm 	register u_int32_t gsbase __asm("ecx");
502c0a54ff6SPeter Wemm 
503c0a54ff6SPeter Wemm 	/*
504c0a54ff6SPeter Wemm 	 * Preserve the gsbase value across the selector load.
505c0a54ff6SPeter Wemm 	 * Note that we have to disable interrupts because the gsbase
506c0a54ff6SPeter Wemm 	 * being trashed happens to be the kernel gsbase at the time.
507c0a54ff6SPeter Wemm 	 */
508c0a54ff6SPeter Wemm 	gsbase = MSR_GSBASE;
509c0a54ff6SPeter Wemm         __asm __volatile("pushfq; cli; rdmsr; movl %0,%%gs; wrmsr; popfq"
510c0a54ff6SPeter Wemm             : : "rm" (sel), "c" (gsbase) : "eax", "edx");
511c0a54ff6SPeter Wemm }
512c0a54ff6SPeter Wemm #else
513c0a54ff6SPeter Wemm /* Usable by userland */
514d85631c4SPeter Wemm static __inline void
5155206bca1SLuoqi Chen load_fs(u_int sel)
5165206bca1SLuoqi Chen {
517e870e9b2SLuoqi Chen 	__asm __volatile("movl %0,%%fs" : : "rm" (sel));
5185206bca1SLuoqi Chen }
5195206bca1SLuoqi Chen 
5205206bca1SLuoqi Chen static __inline void
5215206bca1SLuoqi Chen load_gs(u_int sel)
5225206bca1SLuoqi Chen {
523e870e9b2SLuoqi Chen 	__asm __volatile("movl %0,%%gs" : : "rm" (sel));
5245206bca1SLuoqi Chen }
525c0a54ff6SPeter Wemm #endif
5265206bca1SLuoqi Chen 
527eb1443c8SPeter Wemm /* void lidt(struct region_descriptor *addr); */
528eb1443c8SPeter Wemm static __inline void
529eb1443c8SPeter Wemm lidt(struct region_descriptor *addr)
530eb1443c8SPeter Wemm {
531eb1443c8SPeter Wemm 	__asm __volatile("lidt (%0)" : : "r" (addr));
532eb1443c8SPeter Wemm }
533eb1443c8SPeter Wemm 
534eb1443c8SPeter Wemm /* void lldt(u_short sel); */
535eb1443c8SPeter Wemm static __inline void
536eb1443c8SPeter Wemm lldt(u_short sel)
537eb1443c8SPeter Wemm {
538eb1443c8SPeter Wemm 	__asm __volatile("lldt %0" : : "r" (sel));
539eb1443c8SPeter Wemm }
540eb1443c8SPeter Wemm 
541eb1443c8SPeter Wemm /* void ltr(u_short sel); */
542eb1443c8SPeter Wemm static __inline void
543eb1443c8SPeter Wemm ltr(u_short sel)
544eb1443c8SPeter Wemm {
545eb1443c8SPeter Wemm 	__asm __volatile("ltr %0" : : "r" (sel));
546eb1443c8SPeter Wemm }
547eb1443c8SPeter Wemm 
548ba74981eSWarner Losh static __inline register_t
549ba74981eSWarner Losh intr_disable(void)
550ba74981eSWarner Losh {
551afa88623SPeter Wemm 	register_t rflags;
552ba74981eSWarner Losh 
553afa88623SPeter Wemm 	rflags = read_rflags();
554ba74981eSWarner Losh 	disable_intr();
555afa88623SPeter Wemm 	return (rflags);
556ba74981eSWarner Losh }
557ba74981eSWarner Losh 
558ba74981eSWarner Losh static __inline void
559afa88623SPeter Wemm intr_restore(register_t rflags)
560ba74981eSWarner Losh {
561afa88623SPeter Wemm 	write_rflags(rflags);
562ba74981eSWarner Losh }
563ba74981eSWarner Losh 
564004bedebSBruce Evans #else /* !__GNUC__ */
5655b81b6b3SRodney W. Grimes 
566b63dc6adSAlfred Perlstein int	breakpoint(void);
567b63dc6adSAlfred Perlstein u_int	bsfl(u_int mask);
568b63dc6adSAlfred Perlstein u_int	bsrl(u_int mask);
569afa88623SPeter Wemm void	cpu_invlpg(u_long addr);
570afa88623SPeter Wemm void	cpu_invlpg_range(u_long start, u_long end);
571b63dc6adSAlfred Perlstein void	disable_intr(void);
572b63dc6adSAlfred Perlstein void	do_cpuid(u_int ax, u_int *p);
573b63dc6adSAlfred Perlstein void	enable_intr(void);
574d7ee4425SMark Murray void	halt(void);
575b63dc6adSAlfred Perlstein u_char	inb(u_int port);
576b63dc6adSAlfred Perlstein u_int	inl(u_int port);
577b63dc6adSAlfred Perlstein void	insb(u_int port, void *addr, size_t cnt);
578b63dc6adSAlfred Perlstein void	insl(u_int port, void *addr, size_t cnt);
579b63dc6adSAlfred Perlstein void	insw(u_int port, void *addr, size_t cnt);
580b63dc6adSAlfred Perlstein void	invd(void);
581b63dc6adSAlfred Perlstein void	invlpg(u_int addr);
582f1b665c8SPeter Wemm void	invlpg_range(u_int start, u_int end);
583b63dc6adSAlfred Perlstein void	invltlb(void);
584b63dc6adSAlfred Perlstein u_short	inw(u_int port);
585f1b665c8SPeter Wemm void	load_cr0(u_int cr0);
586f1b665c8SPeter Wemm void	load_cr3(u_int cr3);
587f1b665c8SPeter Wemm void	load_cr4(u_int cr4);
588f1b665c8SPeter Wemm void	load_fs(u_int sel);
589f1b665c8SPeter Wemm void	load_gs(u_int sel);
590eb1443c8SPeter Wemm struct region_descriptor;
591eb1443c8SPeter Wemm void	lidt(struct region_descriptor *addr);
592eb1443c8SPeter Wemm void	lldt(u_short sel);
593eb1443c8SPeter Wemm void	ltr(u_short sel);
594b63dc6adSAlfred Perlstein void	outb(u_int port, u_char data);
595b63dc6adSAlfred Perlstein void	outl(u_int port, u_int data);
596b63dc6adSAlfred Perlstein void	outsb(u_int port, void *addr, size_t cnt);
597b63dc6adSAlfred Perlstein void	outsl(u_int port, void *addr, size_t cnt);
598b63dc6adSAlfred Perlstein void	outsw(u_int port, void *addr, size_t cnt);
599b63dc6adSAlfred Perlstein void	outw(u_int port, u_short data);
6006b8c6989SJohn Baldwin void	ia32_pause(void);
601f1b665c8SPeter Wemm u_int	rcr0(void);
602b63dc6adSAlfred Perlstein u_int	rcr2(void);
603f1b665c8SPeter Wemm u_int	rcr3(void);
604f1b665c8SPeter Wemm u_int	rcr4(void);
605f1b665c8SPeter Wemm u_int	rfs(void);
606f1b665c8SPeter Wemm u_int	rgs(void);
607b63dc6adSAlfred Perlstein u_int64_t rdmsr(u_int msr);
608b63dc6adSAlfred Perlstein u_int64_t rdpmc(u_int pmc);
609b63dc6adSAlfred Perlstein u_int64_t rdtsc(void);
610afa88623SPeter Wemm u_int	read_rflags(void);
611b63dc6adSAlfred Perlstein void	wbinvd(void);
612afa88623SPeter Wemm void	write_rflags(u_int rf);
613b63dc6adSAlfred Perlstein void	wrmsr(u_int msr, u_int64_t newval);
61407508f90SJohn Baldwin void	load_dr7(u_int dr7);
6152be69f32SJohn Baldwin register_t	intr_disable(void);
616afa88623SPeter Wemm void	intr_restore(register_t rf);
617004bedebSBruce Evans 
6185b81b6b3SRodney W. Grimes #endif	/* __GNUC__ */
6195b81b6b3SRodney W. Grimes 
620b63dc6adSAlfred Perlstein void    reset_dbregs(void);
621d74ac681SMatthew Dillon 
62229d5de8aSWarner Losh __END_DECLS
6235b81b6b3SRodney W. Grimes 
624004bedebSBruce Evans #endif /* !_MACHINE_CPUFUNC_H_ */
625