cpufunc.h revision 91367
11573Srgrimes/*-
214272Spst * Copyright (c) 1993 The Regents of the University of California.
31573Srgrimes * All rights reserved.
41573Srgrimes *
51573Srgrimes * Redistribution and use in source and binary forms, with or without
61573Srgrimes * modification, are permitted provided that the following conditions
71573Srgrimes * are met:
81573Srgrimes * 1. Redistributions of source code must retain the above copyright
91573Srgrimes *    notice, this list of conditions and the following disclaimer.
101573Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
111573Srgrimes *    notice, this list of conditions and the following disclaimer in the
121573Srgrimes *    documentation and/or other materials provided with the distribution.
131573Srgrimes * 3. All advertising materials mentioning features or use of this software
141573Srgrimes *    must display the following acknowledgement:
151573Srgrimes *	This product includes software developed by the University of
161573Srgrimes *	California, Berkeley and its contributors.
171573Srgrimes * 4. Neither the name of the University nor the names of its contributors
181573Srgrimes *    may be used to endorse or promote products derived from this software
191573Srgrimes *    without specific prior written permission.
201573Srgrimes *
211573Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
221573Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
231573Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
241573Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
251573Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
261573Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
271573Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
281573Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
291573Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
301573Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
311573Srgrimes * SUCH DAMAGE.
321573Srgrimes *
331573Srgrimes * $FreeBSD: head/sys/amd64/include/cpufunc.h 91367 2002-02-27 09:51:33Z peter $
3414272Spst */
351573Srgrimes
3692986Sobrien/*
3792986Sobrien * Functions to provide access to special i386 instructions.
381573Srgrimes */
391573Srgrimes
401573Srgrimes#ifndef _MACHINE_CPUFUNC_H_
411573Srgrimes#define	_MACHINE_CPUFUNC_H_
421573Srgrimes
431573Srgrimes#include <sys/cdefs.h>
441573Srgrimes#include <machine/psl.h>
451573Srgrimes
461573Srgrimes__BEGIN_DECLS
471573Srgrimes#define readb(va)	(*(volatile u_int8_t *) (va))
481573Srgrimes#define readw(va)	(*(volatile u_int16_t *) (va))
491573Srgrimes#define readl(va)	(*(volatile u_int32_t *) (va))
501573Srgrimes
511573Srgrimes#define writeb(va, d)	(*(volatile u_int8_t *) (va) = (d))
521573Srgrimes#define writew(va, d)	(*(volatile u_int16_t *) (va) = (d))
531573Srgrimes#define writel(va, d)	(*(volatile u_int32_t *) (va) = (d))
541573Srgrimes
551573Srgrimes#define	CRITICAL_FORK	(read_eflags() | PSL_I)
56189291Sdelphij
571573Srgrimes#ifdef	__GNUC__
581573Srgrimes
591573Srgrimes#ifdef SWTCH_OPTIM_STATS
601573Srgrimesextern	int	tlb_flush_count;	/* XXX */
611573Srgrimes#endif
621573Srgrimes
631573Srgrimesstatic __inline void
641573Srgrimesbreakpoint(void)
6514272Spst{
6614272Spst	__asm __volatile("int $3");
67135024Skuriyama}
681573Srgrimes
691573Srgrimesstatic __inline u_int
7014272Spstbsfl(u_int mask)
711573Srgrimes{
721573Srgrimes	u_int	result;
731573Srgrimes
7414272Spst	__asm __volatile("bsfl %1,%0" : "=r" (result) : "rm" (mask));
751573Srgrimes	return (result);
761573Srgrimes}
771573Srgrimes
781573Srgrimesstatic __inline u_int
791573Srgrimesbsrl(u_int mask)
801573Srgrimes{
811573Srgrimes	u_int	result;
821573Srgrimes
831573Srgrimes	__asm __volatile("bsrl %1,%0" : "=r" (result) : "rm" (mask));
841573Srgrimes	return (result);
851573Srgrimes}
861573Srgrimes
871573Srgrimesstatic __inline void
881573Srgrimesdisable_intr(void)
891573Srgrimes{
901573Srgrimes	__asm __volatile("cli" : : : "memory");
911573Srgrimes}
921573Srgrimes
931573Srgrimesstatic __inline void
941573Srgrimesenable_intr(void)
951573Srgrimes{
961573Srgrimes	__asm __volatile("sti");
971573Srgrimes}
981573Srgrimes
99189291Sdelphij#define	HAVE_INLINE_FFS
1001573Srgrimes
1011573Srgrimesstatic __inline int
1021573Srgrimesffs(int mask)
1031573Srgrimes{
1041573Srgrimes	/*
105135024Skuriyama	 * Note that gcc-2's builtin ffs would be used if we didn't declare
106135024Skuriyama	 * this inline or turn off the builtin.  The builtin is faster but
107135024Skuriyama	 * broken in gcc-2.4.5 and slower but working in gcc-2.5 and later
108135024Skuriyama	 * versions.
109135024Skuriyama	 */
110135024Skuriyama	 return (mask == 0 ? mask : bsfl((u_int)mask) + 1);
1111573Srgrimes}
1121573Srgrimes
11314272Spst#define	HAVE_INLINE_FLS
1141573Srgrimes
1151573Srgrimesstatic __inline int
1161573Srgrimesfls(int mask)
11714272Spst{
1181573Srgrimes	return (mask == 0 ? mask : bsrl((u_int)mask) + 1);
1191573Srgrimes}
1201573Srgrimes
1211573Srgrimes#if __GNUC__ < 2
1221573Srgrimes
1231573Srgrimes#define	inb(port)		inbv(port)
1241573Srgrimes#define	outb(port, data)	outbv(port, data)
1251573Srgrimes
1261573Srgrimes#else /* __GNUC >= 2 */
1271573Srgrimes
1281573Srgrimes/*
1291573Srgrimes * The following complications are to get around gcc not having a
1301573Srgrimes * constraint letter for the range 0..255.  We still put "d" in the
1311573Srgrimes * constraint because "i" isn't a valid constraint when the port
132189291Sdelphij * isn't constant.  This only matters for -O0 because otherwise
1331573Srgrimes * the non-working version gets optimized away.
1341573Srgrimes *
1351573Srgrimes * Use an expression-statement instead of a conditional expression
1361573Srgrimes * because gcc-2.6.0 would promote the operands of the conditional
1371573Srgrimes * and produce poor code for "if ((inb(var) & const1) == const2)".
1381573Srgrimes *
1391573Srgrimes * The unnecessary test `(port) < 0x10000' is to generate a warning if
1401573Srgrimes * the `port' has type u_short or smaller.  Such types are pessimal.
1411573Srgrimes * This actually only works for signed types.  The range check is
1421573Srgrimes * careful to avoid generating warnings.
1431573Srgrimes */
1441573Srgrimes#define	inb(port) __extension__ ({					\
1451573Srgrimes	u_char	_data;							\
1461573Srgrimes	if (__builtin_constant_p(port) && ((port) & 0xffff) < 0x100	\
1471573Srgrimes	    && (port) < 0x10000)					\
1481573Srgrimes		_data = inbc(port);					\
1491573Srgrimes	else								\
1501573Srgrimes		_data = inbv(port);					\
151189291Sdelphij	_data; })
1521573Srgrimes
1531573Srgrimes#define	outb(port, data) (						\
1541573Srgrimes	__builtin_constant_p(port) && ((port) & 0xffff) < 0x100		\
1551573Srgrimes	&& (port) < 0x10000						\
1561573Srgrimes	? outbc(port, data) : outbv(port, data))
1571573Srgrimes
1581573Srgrimesstatic __inline u_char
1591573Srgrimesinbc(u_int port)
1601573Srgrimes{
1611573Srgrimes	u_char	data;
1621573Srgrimes
1631573Srgrimes	__asm __volatile("inb %1,%0" : "=a" (data) : "id" ((u_short)(port)));
1641573Srgrimes	return (data);
1651573Srgrimes}
1661573Srgrimes
1671573Srgrimesstatic __inline void
1681573Srgrimesoutbc(u_int port, u_char data)
1691573Srgrimes{
1701573Srgrimes	__asm __volatile("outb %0,%1" : : "a" (data), "id" ((u_short)(port)));
1711573Srgrimes}
1721573Srgrimes
1731573Srgrimes#endif /* __GNUC <= 2 */
1741573Srgrimes
1751573Srgrimesstatic __inline u_char
1761573Srgrimesinbv(u_int port)
1771573Srgrimes{
1781573Srgrimes	u_char	data;
1791573Srgrimes	/*
1801573Srgrimes	 * We use %%dx and not %1 here because i/o is done at %dx and not at
1811573Srgrimes	 * %edx, while gcc generates inferior code (movw instead of movl)
1821573Srgrimes	 * if we tell it to load (u_short) port.
1831573Srgrimes	 */
1841573Srgrimes	__asm __volatile("inb %%dx,%0" : "=a" (data) : "d" (port));
1851573Srgrimes	return (data);
18614272Spst}
1871573Srgrimes
1881573Srgrimesstatic __inline u_int
1891573Srgrimesinl(u_int port)
1901573Srgrimes{
1911573Srgrimes	u_int	data;
1921573Srgrimes
1931573Srgrimes	__asm __volatile("inl %%dx,%0" : "=a" (data) : "d" (port));
1941573Srgrimes	return (data);
1951573Srgrimes}
1961573Srgrimes
1971573Srgrimesstatic __inline void
1981573Srgrimesinsb(u_int port, void *addr, size_t cnt)
1991573Srgrimes{
2001573Srgrimes	__asm __volatile("cld; rep; insb"
2011573Srgrimes			 : "+D" (addr), "+c" (cnt)
2021573Srgrimes			 : "d" (port)
2031573Srgrimes			 : "memory");
2041573Srgrimes}
2051573Srgrimes
206135024Skuriyamastatic __inline void
2071573Srgrimesinsw(u_int port, void *addr, size_t cnt)
20814272Spst{
2091573Srgrimes	__asm __volatile("cld; rep; insw"
210135024Skuriyama			 : "+D" (addr), "+c" (cnt)
211135024Skuriyama			 : "d" (port)
2121573Srgrimes			 : "memory");
2131573Srgrimes}
214135024Skuriyama
2151573Srgrimesstatic __inline void
21614272Spstinsl(u_int port, void *addr, size_t cnt)
2171573Srgrimes{
2181573Srgrimes	__asm __volatile("cld; rep; insl"
2191573Srgrimes			 : "+D" (addr), "+c" (cnt)
2201573Srgrimes			 : "d" (port)
2211573Srgrimes			 : "memory");
2221573Srgrimes}
2231573Srgrimes
2241573Srgrimesstatic __inline void
2251573Srgrimesinvd(void)
226135024Skuriyama{
2271573Srgrimes	__asm __volatile("invd");
22814272Spst}
2291573Srgrimes
2301573Srgrimes#if defined(SMP) && defined(_KERNEL)
2311573Srgrimes
2321573Srgrimes/*
2331573Srgrimes * When using APIC IPI's, invlpg() is not simply the invlpg instruction
2341573Srgrimes * (this is a bug) and the inlining cost is prohibitive since the call
2351573Srgrimes * executes into the IPI transmission system.
2361573Srgrimes */
2371573Srgrimesvoid	invlpg		__P((u_int addr));
2381573Srgrimesvoid	invltlb		__P((void));
2391573Srgrimes
2401573Srgrimesstatic __inline void
2411573Srgrimescpu_invlpg(void *addr)
2421573Srgrimes{
2431573Srgrimes	__asm __volatile("invlpg %0" : : "m" (*(char *)addr) : "memory");
2441573Srgrimes}
2451573Srgrimes
2461573Srgrimesstatic __inline void
247189291Sdelphijcpu_invltlb(void)
2481573Srgrimes{
2491573Srgrimes	u_int	temp;
2501573Srgrimes	/*
2511573Srgrimes	 * This should be implemented as load_cr3(rcr3()) when load_cr3()
2521573Srgrimes	 * is inlined.
2531573Srgrimes	 */
2541573Srgrimes	__asm __volatile("movl %%cr3, %0; movl %0, %%cr3" : "=r" (temp)
2551573Srgrimes			 : : "memory");
2561573Srgrimes#if defined(SWTCH_OPTIM_STATS)
2571573Srgrimes	++tlb_flush_count;
2581573Srgrimes#endif
2591573Srgrimes}
2601573Srgrimes
26114272Spst#else /* !(SMP && _KERNEL) */
2621573Srgrimes
2631573Srgrimesstatic __inline void
2641573Srgrimesinvlpg(u_int addr)
2651573Srgrimes{
2661573Srgrimes	__asm __volatile("invlpg %0" : : "m" (*(char *)addr) : "memory");
2671573Srgrimes}
2681573Srgrimes
2691573Srgrimesstatic __inline void
2701573Srgrimesinvltlb(void)
2711573Srgrimes{
2721573Srgrimes	u_int	temp;
2731573Srgrimes	/*
2741573Srgrimes	 * This should be implemented as load_cr3(rcr3()) when load_cr3()
2751573Srgrimes	 * is inlined.
2761573Srgrimes	 */
2771573Srgrimes	__asm __volatile("movl %%cr3, %0; movl %0, %%cr3" : "=r" (temp)
2781573Srgrimes			 : : "memory");
2791573Srgrimes#ifdef SWTCH_OPTIM_STATS
2801573Srgrimes	++tlb_flush_count;
2811573Srgrimes#endif
2821573Srgrimes}
2831573Srgrimes
2841573Srgrimes#endif /* SMP && _KERNEL */
2851573Srgrimes
2861573Srgrimesstatic __inline u_short
2871573Srgrimesinw(u_int port)
2881573Srgrimes{
28914272Spst	u_short	data;
2901573Srgrimes
2911573Srgrimes	__asm __volatile("inw %%dx,%0" : "=a" (data) : "d" (port));
2921573Srgrimes	return (data);
2931573Srgrimes}
2941573Srgrimes
2951573Srgrimesstatic __inline void
2961573Srgrimesoutbv(u_int port, u_char data)
29714272Spst{
298135024Skuriyama	u_char	al;
2991573Srgrimes	/*
300135024Skuriyama	 * Use an unnecessary assignment to help gcc's register allocator.
3011573Srgrimes	 * This make a large difference for gcc-1.40 and a tiny difference
3021573Srgrimes	 * for gcc-2.6.0.  For gcc-1.40, al had to be ``asm("ax")'' for
3031573Srgrimes	 * best results.  gcc-2.6.0 can't handle this.
304135024Skuriyama	 */
3051573Srgrimes	al = data;
3061573Srgrimes	__asm __volatile("outb %0,%%dx" : : "a" (al), "d" (port));
3071573Srgrimes}
3081573Srgrimes
3091573Srgrimesstatic __inline void
3101573Srgrimesoutl(u_int port, u_int data)
3111573Srgrimes{
3121573Srgrimes	/*
3131573Srgrimes	 * outl() and outw() aren't used much so we haven't looked at
3141573Srgrimes	 * possible micro-optimizations such as the unnecessary
3151573Srgrimes	 * assignment for them.
3161573Srgrimes	 */
3171573Srgrimes	__asm __volatile("outl %0,%%dx" : : "a" (data), "d" (port));
3181573Srgrimes}
3191573Srgrimes
3201573Srgrimesstatic __inline void
3211573Srgrimesoutsb(u_int port, const void *addr, size_t cnt)
3221573Srgrimes{
323	__asm __volatile("cld; rep; outsb"
324			 : "+S" (addr), "+c" (cnt)
325			 : "d" (port));
326}
327
328static __inline void
329outsw(u_int port, const void *addr, size_t cnt)
330{
331	__asm __volatile("cld; rep; outsw"
332			 : "+S" (addr), "+c" (cnt)
333			 : "d" (port));
334}
335
336static __inline void
337outsl(u_int port, const void *addr, size_t cnt)
338{
339	__asm __volatile("cld; rep; outsl"
340			 : "+S" (addr), "+c" (cnt)
341			 : "d" (port));
342}
343
344static __inline void
345outw(u_int port, u_short data)
346{
347	__asm __volatile("outw %0,%%dx" : : "a" (data), "d" (port));
348}
349
350static __inline u_int
351rcr2(void)
352{
353	u_int	data;
354
355	__asm __volatile("movl %%cr2,%0" : "=r" (data));
356	return (data);
357}
358
359static __inline u_int
360read_eflags(void)
361{
362	u_int	ef;
363
364	__asm __volatile("pushfl; popl %0" : "=r" (ef));
365	return (ef);
366}
367
368static __inline void
369do_cpuid(u_int ax, u_int *p)
370{
371	__asm __volatile(
372	"cpuid"
373	: "=a" (p[0]), "=b" (p[1]), "=c" (p[2]), "=d" (p[3])
374	:  "0" (ax)
375	);
376}
377
378static __inline u_int64_t
379rdmsr(u_int msr)
380{
381	u_int64_t rv;
382
383	__asm __volatile("rdmsr" : "=A" (rv) : "c" (msr));
384	return (rv);
385}
386
387static __inline u_int64_t
388rdpmc(u_int pmc)
389{
390	u_int64_t rv;
391
392	__asm __volatile("rdpmc" : "=A" (rv) : "c" (pmc));
393	return (rv);
394}
395
396static __inline u_int64_t
397rdtsc(void)
398{
399	u_int64_t rv;
400
401	__asm __volatile("rdtsc" : "=A" (rv));
402	return (rv);
403}
404
405static __inline void
406wbinvd(void)
407{
408	__asm __volatile("wbinvd");
409}
410
411static __inline void
412write_eflags(u_int ef)
413{
414	__asm __volatile("pushl %0; popfl" : : "r" (ef));
415}
416
417static __inline void
418wrmsr(u_int msr, u_int64_t newval)
419{
420	__asm __volatile("wrmsr" : : "A" (newval), "c" (msr));
421}
422
423static __inline u_int
424rfs(void)
425{
426	u_int sel;
427	__asm __volatile("movl %%fs,%0" : "=rm" (sel));
428	return (sel);
429}
430
431static __inline u_int
432rgs(void)
433{
434	u_int sel;
435	__asm __volatile("movl %%gs,%0" : "=rm" (sel));
436	return (sel);
437}
438
439static __inline void
440load_fs(u_int sel)
441{
442	__asm __volatile("movl %0,%%fs" : : "rm" (sel));
443}
444
445static __inline void
446load_gs(u_int sel)
447{
448	__asm __volatile("movl %0,%%gs" : : "rm" (sel));
449}
450
451static __inline u_int
452rdr0(void)
453{
454	u_int	data;
455	__asm __volatile("movl %%dr0,%0" : "=r" (data));
456	return (data);
457}
458
459static __inline void
460load_dr0(u_int sel)
461{
462	__asm __volatile("movl %0,%%dr0" : : "r" (sel));
463}
464
465static __inline u_int
466rdr1(void)
467{
468	u_int	data;
469	__asm __volatile("movl %%dr1,%0" : "=r" (data));
470	return (data);
471}
472
473static __inline void
474load_dr1(u_int sel)
475{
476	__asm __volatile("movl %0,%%dr1" : : "r" (sel));
477}
478
479static __inline u_int
480rdr2(void)
481{
482	u_int	data;
483	__asm __volatile("movl %%dr2,%0" : "=r" (data));
484	return (data);
485}
486
487static __inline void
488load_dr2(u_int sel)
489{
490	__asm __volatile("movl %0,%%dr2" : : "r" (sel));
491}
492
493static __inline u_int
494rdr3(void)
495{
496	u_int	data;
497	__asm __volatile("movl %%dr3,%0" : "=r" (data));
498	return (data);
499}
500
501static __inline void
502load_dr3(u_int sel)
503{
504	__asm __volatile("movl %0,%%dr3" : : "r" (sel));
505}
506
507static __inline u_int
508rdr4(void)
509{
510	u_int	data;
511	__asm __volatile("movl %%dr4,%0" : "=r" (data));
512	return (data);
513}
514
515static __inline void
516load_dr4(u_int sel)
517{
518	__asm __volatile("movl %0,%%dr4" : : "r" (sel));
519}
520
521static __inline u_int
522rdr5(void)
523{
524	u_int	data;
525	__asm __volatile("movl %%dr5,%0" : "=r" (data));
526	return (data);
527}
528
529static __inline void
530load_dr5(u_int sel)
531{
532	__asm __volatile("movl %0,%%dr5" : : "r" (sel));
533}
534
535static __inline u_int
536rdr6(void)
537{
538	u_int	data;
539	__asm __volatile("movl %%dr6,%0" : "=r" (data));
540	return (data);
541}
542
543static __inline void
544load_dr6(u_int sel)
545{
546	__asm __volatile("movl %0,%%dr6" : : "r" (sel));
547}
548
549static __inline u_int
550rdr7(void)
551{
552	u_int	data;
553	__asm __volatile("movl %%dr7,%0" : "=r" (data));
554	return (data);
555}
556
557static __inline void
558load_dr7(u_int sel)
559{
560	__asm __volatile("movl %0,%%dr7" : : "r" (sel));
561}
562
563static __inline critical_t
564cpu_critical_enter(void)
565{
566	critical_t eflags;
567
568	eflags = read_eflags();
569	disable_intr();
570	return (eflags);
571}
572
573static __inline void
574cpu_critical_exit(critical_t eflags)
575{
576	write_eflags(eflags);
577}
578
579#else /* !__GNUC__ */
580
581int	breakpoint	__P((void));
582u_int	bsfl		__P((u_int mask));
583u_int	bsrl		__P((u_int mask));
584void	disable_intr	__P((void));
585void	do_cpuid	__P((u_int ax, u_int *p));
586void	enable_intr	__P((void));
587u_char	inb		__P((u_int port));
588u_int	inl		__P((u_int port));
589void	insb		__P((u_int port, void *addr, size_t cnt));
590void	insl		__P((u_int port, void *addr, size_t cnt));
591void	insw		__P((u_int port, void *addr, size_t cnt));
592void	invd		__P((void));
593void	invlpg		__P((u_int addr));
594void	invltlb		__P((void));
595u_short	inw		__P((u_int port));
596void	outb		__P((u_int port, u_char data));
597void	outl		__P((u_int port, u_int data));
598void	outsb		__P((u_int port, void *addr, size_t cnt));
599void	outsl		__P((u_int port, void *addr, size_t cnt));
600void	outsw		__P((u_int port, void *addr, size_t cnt));
601void	outw		__P((u_int port, u_short data));
602u_int	rcr2		__P((void));
603u_int64_t rdmsr		__P((u_int msr));
604u_int64_t rdpmc		__P((u_int pmc));
605u_int64_t rdtsc		__P((void));
606u_int	read_eflags	__P((void));
607void	wbinvd		__P((void));
608void	write_eflags	__P((u_int ef));
609void	wrmsr		__P((u_int msr, u_int64_t newval));
610u_int	rfs		__P((void));
611u_int	rgs		__P((void));
612void	load_fs		__P((u_int sel));
613void	load_gs		__P((u_int sel));
614critical_t cpu_critical_enter __P((void));
615void	cpu_critical_exit __P((critical_t eflags));
616
617#endif	/* __GNUC__ */
618
619void	load_cr0	__P((u_int cr0));
620void	load_cr3	__P((u_int cr3));
621void	load_cr4	__P((u_int cr4));
622void	ltr		__P((u_short sel));
623u_int	rcr0		__P((void));
624u_int	rcr3		__P((void));
625u_int	rcr4		__P((void));
626void    reset_dbregs    __P((void));
627__END_DECLS
628
629#endif /* !_MACHINE_CPUFUNC_H_ */
630