cpufunc.h revision 125175
1139749Simp/*-
239223Sgibbs * Copyright (c) 2003 Peter Wemm.
339223Sgibbs * Copyright (c) 1993 The Regents of the University of California.
439223Sgibbs * All rights reserved.
544579Sgibbs *
639223Sgibbs * Redistribution and use in source and binary forms, with or without
739223Sgibbs * modification, are permitted provided that the following conditions
839223Sgibbs * are met:
939223Sgibbs * 1. Redistributions of source code must retain the above copyright
1039223Sgibbs *    notice, this list of conditions and the following disclaimer.
1139223Sgibbs * 2. Redistributions in binary form must reproduce the above copyright
1239223Sgibbs *    notice, this list of conditions and the following disclaimer in the
1339223Sgibbs *    documentation and/or other materials provided with the distribution.
1439223Sgibbs * 3. All advertising materials mentioning features or use of this software
1539223Sgibbs *    must display the following acknowledgement:
1639223Sgibbs *	This product includes software developed by the University of
1739223Sgibbs *	California, Berkeley and its contributors.
1839223Sgibbs * 4. Neither the name of the University nor the names of its contributors
1939223Sgibbs *    may be used to endorse or promote products derived from this software
2039223Sgibbs *    without specific prior written permission.
2139223Sgibbs *
2239223Sgibbs * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2339223Sgibbs * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2439223Sgibbs * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2539223Sgibbs * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2639223Sgibbs * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2739223Sgibbs * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2839223Sgibbs * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2939223Sgibbs * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
3039223Sgibbs * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31119418Sobrien * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32119418Sobrien * SUCH DAMAGE.
33119418Sobrien *
3439223Sgibbs * $FreeBSD: head/sys/amd64/include/cpufunc.h 125175 2004-01-28 23:53:04Z peter $
3539223Sgibbs */
3645791Speter
3745791Speter/*
38117126Sscottl * Functions to provide access to special i386 instructions.
39117126Sscottl * This in included in sys/systm.h, and that file should be
4045791Speter * used in preference to this.
4139223Sgibbs */
4239223Sgibbs
4345791Speter#ifndef _MACHINE_CPUFUNC_H_
4445791Speter#define	_MACHINE_CPUFUNC_H_
4539223Sgibbs
4645791Speter#include <sys/cdefs.h>
4739223Sgibbs#include <machine/psl.h>
4839223Sgibbs
4939223Sgibbsstruct thread;
5039223Sgibbsstruct region_descriptor;
5139223Sgibbs
5239223Sgibbs__BEGIN_DECLS
5339223Sgibbs#define readb(va)	(*(volatile u_int8_t *) (va))
5445791Speter#define readw(va)	(*(volatile u_int16_t *) (va))
5547399Sdfr#define readl(va)	(*(volatile u_int32_t *) (va))
5639223Sgibbs#define readq(va)	(*(volatile u_int64_t *) (va))
5745791Speter
5845791Speter#define writeb(va, d)	(*(volatile u_int8_t *) (va) = (d))
5945791Speter#define writew(va, d)	(*(volatile u_int16_t *) (va) = (d))
6045791Speter#define writel(va, d)	(*(volatile u_int32_t *) (va) = (d))
6139223Sgibbs#define writeq(va, d)	(*(volatile u_int64_t *) (va) = (d))
6245791Speter
6345791Speter#ifdef	__GNUC__
6447399Sdfr
6545791Speterstatic __inline void
6645791Speterbreakpoint(void)
6745791Speter{
6845791Speter	__asm __volatile("int $3");
6945791Speter}
70127135Snjl
7145791Speterstatic __inline u_int
7245791Speterbsfl(u_int mask)
7345791Speter{
7445791Speter	u_int	result;
7545791Speter
7645791Speter	__asm __volatile("bsfl %1,%0" : "=r" (result) : "rm" (mask));
7745791Speter	return (result);
78241592Sjhb}
7945791Speter
8045791Speterstatic __inline u_long
8145791Speterbsfq(u_long mask)
82127135Snjl{
8345791Speter	u_long	result;
8445791Speter
8545791Speter	__asm __volatile("bsfq %1,%0" : "=r" (result) : "rm" (mask));
8645791Speter	return (result);
8745791Speter}
8845791Speter
8945791Speterstatic __inline u_int
9045791Speterbsrl(u_int mask)
9145791Speter{
9245791Speter	u_int	result;
93241592Sjhb
9445791Speter	__asm __volatile("bsrl %1,%0" : "=r" (result) : "rm" (mask));
9545791Speter	return (result);
9645791Speter}
9745791Speter
9845791Speterstatic __inline u_long
9945791Speterbsrq(u_long mask)
10045791Speter{
10145791Speter	u_long	result;
10245791Speter
10345791Speter	__asm __volatile("bsrq %1,%0" : "=r" (result) : "rm" (mask));
10445791Speter	return (result);
10545791Speter}
10645791Speter
10745791Speterstatic __inline void
10845796Speterdisable_intr(void)
10945791Speter{
11045796Speter	__asm __volatile("cli" : : : "memory");
11145791Speter}
11245791Speter
11345791Speterstatic __inline void
11439223Sgibbsdo_cpuid(u_int ax, u_int *p)
11539223Sgibbs{
11639223Sgibbs	__asm __volatile("cpuid"
11739223Sgibbs			 : "=a" (p[0]), "=b" (p[1]), "=c" (p[2]), "=d" (p[3])
11839223Sgibbs			 :  "0" (ax));
11939223Sgibbs}
12039223Sgibbs
12145791Speterstatic __inline void
12239223Sgibbsenable_intr(void)
12339223Sgibbs{
12439223Sgibbs	__asm __volatile("sti");
12539223Sgibbs}
12639223Sgibbs
12739223Sgibbs#define	HAVE_INLINE_FFS
12839223Sgibbs
12947617Sdfrstatic __inline int
13047617Sdfrffs(int mask)
13147617Sdfr{
13247617Sdfr#if 0
13339223Sgibbs	/*
13439223Sgibbs	 * Note that gcc-2's builtin ffs would be used if we didn't declare
13539223Sgibbs	 * this inline or turn off the builtin.  The builtin is faster but
13639223Sgibbs	 * broken in gcc-2.4.5 and slower but working in gcc-2.5 and later
13739223Sgibbs	 * versions.
13839223Sgibbs	 */
13945791Speter	return (mask == 0 ? mask : (int)bsfl((u_int)mask) + 1);
14039223Sgibbs#else
14141048Sgibbs	/* Actually, the above is way out of date.  The builtins use cmov etc */
14245791Speter	return (__builtin_ffs(mask));
14341048Sgibbs#endif
14439223Sgibbs}
14539223Sgibbs
14644579Sgibbs#define	HAVE_INLINE_FFSL
14739223Sgibbs
14839223Sgibbsstatic __inline int
14941048Sgibbsffsl(long mask)
15039223Sgibbs{
15139223Sgibbs	return (mask == 0 ? mask : (int)bsfq((u_long)mask) + 1);
15239223Sgibbs}
15340265Simp
15439223Sgibbs#define	HAVE_INLINE_FLS
15539223Sgibbs
15639223Sgibbsstatic __inline int
15745791Speterfls(int mask)
15845791Speter{
15947399Sdfr	return (mask == 0 ? mask : (int)bsrl((u_int)mask) + 1);
16047399Sdfr}
16140160Simp
16240160Simp#define	HAVE_INLINE_FLSL
16339223Sgibbs
16439223Sgibbsstatic __inline int
16539223Sgibbsflsl(long mask)
16645791Speter{
16747717Speter	return (mask == 0 ? mask : (int)bsrq((u_long)mask) + 1);
16847717Speter}
16947717Speter
17045791Speterstatic __inline void
17139223Sgibbshalt(void)
17239223Sgibbs{
17339223Sgibbs	__asm __volatile("hlt");
17445791Speter}
17540160Simp
17652174Sdfr#if __GNUC__ < 2
17752174Sdfr
17845791Speter#define	inb(port)		inbv(port)
179241592Sjhb#define	outb(port, data)	outbv(port, data)
18039223Sgibbs
18139223Sgibbs#else /* __GNUC >= 2 */
18245791Speter
18339223Sgibbs/*
18439223Sgibbs * The following complications are to get around gcc not having a
18539223Sgibbs * constraint letter for the range 0..255.  We still put "d" in the
18639223Sgibbs * constraint because "i" isn't a valid constraint when the port
18739223Sgibbs * isn't constant.  This only matters for -O0 because otherwise
18839223Sgibbs * the non-working version gets optimized away.
18945791Speter *
19039223Sgibbs * Use an expression-statement instead of a conditional expression
19145791Speter * because gcc-2.6.0 would promote the operands of the conditional
19239223Sgibbs * and produce poor code for "if ((inb(var) & const1) == const2)".
19339223Sgibbs *
19439223Sgibbs * The unnecessary test `(port) < 0x10000' is to generate a warning if
19545796Speter * the `port' has type u_short or smaller.  Such types are pessimal.
19639223Sgibbs * This actually only works for signed types.  The range check is
19745791Speter * careful to avoid generating warnings.
19847399Sdfr */
19945791Speter#define	inb(port) __extension__ ({					\
20045791Speter	u_char	_data;							\
20145791Speter	if (__builtin_constant_p(port) && ((port) & 0xffff) < 0x100	\
20245791Speter	    && (port) < 0x10000)					\
20339223Sgibbs		_data = inbc(port);					\
20445796Speter	else								\
20545796Speter		_data = inbv(port);					\
20645796Speter	_data; })
20745796Speter
20839223Sgibbs#define	outb(port, data) (						\
20939223Sgibbs	__builtin_constant_p(port) && ((port) & 0xffff) < 0x100		\
21039223Sgibbs	&& (port) < 0x10000						\
21139223Sgibbs	? outbc(port, data) : outbv(port, data))
21239223Sgibbs
21339223Sgibbsstatic __inline u_char
21439223Sgibbsinbc(u_int port)
21539223Sgibbs{
21639223Sgibbs	u_char	data;
21739223Sgibbs
21839223Sgibbs	__asm __volatile("inb %1,%0" : "=a" (data) : "id" ((u_short)(port)));
21939223Sgibbs	return (data);
22039223Sgibbs}
22139223Sgibbs
22239223Sgibbsstatic __inline void
22339223Sgibbsoutbc(u_int port, u_char data)
22439223Sgibbs{
22539223Sgibbs	__asm __volatile("outb %0,%1" : : "a" (data), "id" ((u_short)(port)));
22639223Sgibbs}
22739223Sgibbs
22839223Sgibbs#endif /* __GNUC <= 2 */
22939223Sgibbs
23039223Sgibbsstatic __inline u_char
23139223Sgibbsinbv(u_int port)
23239223Sgibbs{
23339223Sgibbs	u_char	data;
23439223Sgibbs	/*
23539223Sgibbs	 * We use %%dx and not %1 here because i/o is done at %dx and not at
236241592Sjhb	 * %edx, while gcc generates inferior code (movw instead of movl)
237112782Smdodd	 * if we tell it to load (u_short) port.
238112782Smdodd	 */
239112782Smdodd	__asm __volatile("inb %%dx,%0" : "=a" (data) : "d" (port));
240112782Smdodd	return (data);
241112782Smdodd}
242112782Smdodd
243112782Smdoddstatic __inline u_int
244112782Smdoddinl(u_int port)
245112782Smdodd{
246112782Smdodd	u_int	data;
247241592Sjhb
248241592Sjhb	__asm __volatile("inl %%dx,%0" : "=a" (data) : "d" (port));
249112782Smdodd	return (data);
25045791Speter}
25145791Speter
25239223Sgibbsstatic __inline void
25339223Sgibbsinsb(u_int port, void *addr, size_t cnt)
25445796Speter{
25545796Speter	__asm __volatile("cld; rep; insb"
25645791Speter			 : "+D" (addr), "+c" (cnt)
25745791Speter			 : "d" (port)
25839223Sgibbs			 : "memory");
25939223Sgibbs}
26039223Sgibbs
26139223Sgibbsstatic __inline void
262112782Smdoddinsw(u_int port, void *addr, size_t cnt)
263112782Smdodd{
264112782Smdodd	__asm __volatile("cld; rep; insw"
265112782Smdodd			 : "+D" (addr), "+c" (cnt)
266112782Smdodd			 : "d" (port)
267112782Smdodd			 : "memory");
268112782Smdodd}
269112782Smdodd
270112782Smdoddstatic __inline void
271112782Smdoddinsl(u_int port, void *addr, size_t cnt)
272112782Smdodd{
273112782Smdodd	__asm __volatile("cld; rep; insl"
274112782Smdodd			 : "+D" (addr), "+c" (cnt)
275241592Sjhb			 : "d" (port)
276241592Sjhb			 : "memory");
277112782Smdodd}
27845791Speter
27945791Speterstatic __inline void
28039223Sgibbsinvd(void)
28139223Sgibbs{
28239223Sgibbs	__asm __volatile("invd");
28339223Sgibbs}
28439223Sgibbs
28539223Sgibbsstatic __inline u_short
28639223Sgibbsinw(u_int port)
28739223Sgibbs{
28845791Speter	u_short	data;
28945791Speter
29039223Sgibbs	__asm __volatile("inw %%dx,%0" : "=a" (data) : "d" (port));
29139223Sgibbs	return (data);
29239223Sgibbs}
29339223Sgibbs
29439223Sgibbsstatic __inline void
29539223Sgibbsoutbv(u_int port, u_char data)
29639223Sgibbs{
29739223Sgibbs	u_char	al;
29839223Sgibbs	/*
29939223Sgibbs	 * Use an unnecessary assignment to help gcc's register allocator.
30039223Sgibbs	 * This make a large difference for gcc-1.40 and a tiny difference
30139223Sgibbs	 * for gcc-2.6.0.  For gcc-1.40, al had to be ``asm("ax")'' for
30239223Sgibbs	 * best results.  gcc-2.6.0 can't handle this.
30345791Speter	 */
30445791Speter	al = data;
30545791Speter	__asm __volatile("outb %0,%%dx" : : "a" (al), "d" (port));
30645791Speter}
30745791Speter
30839223Sgibbsstatic __inline void
30945791Speteroutl(u_int port, u_int data)
31039223Sgibbs{
31139223Sgibbs	/*
31239223Sgibbs	 * outl() and outw() aren't used much so we haven't looked at
31339223Sgibbs	 * possible micro-optimizations such as the unnecessary
31439223Sgibbs	 * assignment for them.
31539223Sgibbs	 */
31639223Sgibbs	__asm __volatile("outl %0,%%dx" : : "a" (data), "d" (port));
31739223Sgibbs}
31839223Sgibbs
31939223Sgibbsstatic __inline void
32039223Sgibbsoutsb(u_int port, const void *addr, size_t cnt)
32139223Sgibbs{
32239223Sgibbs	__asm __volatile("cld; rep; outsb"
32339223Sgibbs			 : "+S" (addr), "+c" (cnt)
32439223Sgibbs			 : "d" (port));
32539223Sgibbs}
32639223Sgibbs
32739223Sgibbsstatic __inline void
32839223Sgibbsoutsw(u_int port, const void *addr, size_t cnt)
32939223Sgibbs{
33039223Sgibbs	__asm __volatile("cld; rep; outsw"
33139223Sgibbs			 : "+S" (addr), "+c" (cnt)
33239223Sgibbs			 : "d" (port));
33339223Sgibbs}
33439223Sgibbs
33539223Sgibbsstatic __inline void
33639223Sgibbsoutsl(u_int port, const void *addr, size_t cnt)
33739223Sgibbs{
33845791Speter	__asm __volatile("cld; rep; outsl"
33945791Speter			 : "+S" (addr), "+c" (cnt)
34045791Speter			 : "d" (port));
34145791Speter}
34245791Speter
34345791Speterstatic __inline void
34445791Speteroutw(u_int port, u_short data)
34545791Speter{
34645791Speter	__asm __volatile("outw %0,%%dx" : : "a" (data), "d" (port));
34745791Speter}
34845791Speter
34945791Speterstatic __inline void
35045791Speteria32_pause(void)
35145791Speter{
35245791Speter	__asm __volatile("pause");
35345791Speter}
35445791Speter
35545791Speterstatic __inline u_long
356165102Smjacobread_rflags(void)
357{
358	u_long	rf;
359
360	__asm __volatile("pushfq; popq %0" : "=r" (rf));
361	return (rf);
362}
363
364static __inline u_int64_t
365rdmsr(u_int msr)
366{
367	u_int32_t low, high;
368
369	__asm __volatile("rdmsr" : "=a" (low), "=d" (high) : "c" (msr));
370	return (low | ((u_int64_t)high << 32));
371}
372
373static __inline u_int64_t
374rdpmc(u_int pmc)
375{
376	u_int32_t low, high;
377
378	__asm __volatile("rdpmc" : "=a" (low), "=d" (high) : "c" (pmc));
379	return (low | ((u_int64_t)high << 32));
380}
381
382static __inline u_int64_t
383rdtsc(void)
384{
385	u_int32_t low, high;
386
387	__asm __volatile("rdtsc" : "=a" (low), "=d" (high));
388	return (low | ((u_int64_t)high << 32));
389}
390
391static __inline void
392wbinvd(void)
393{
394	__asm __volatile("wbinvd");
395}
396
397static __inline void
398write_rflags(u_long rf)
399{
400	__asm __volatile("pushq %0;  popfq" : : "r" (rf));
401}
402
403static __inline void
404wrmsr(u_int msr, u_int64_t newval)
405{
406	u_int32_t low, high;
407
408	low = newval;
409	high = newval >> 32;
410	__asm __volatile("wrmsr" : : "a" (low), "d" (high), "c" (msr));
411}
412
413static __inline void
414load_cr0(u_long data)
415{
416
417	__asm __volatile("movq %0,%%cr0" : : "r" (data));
418}
419
420static __inline u_long
421rcr0(void)
422{
423	u_long	data;
424
425	__asm __volatile("movq %%cr0,%0" : "=r" (data));
426	return (data);
427}
428
429static __inline u_long
430rcr2(void)
431{
432	u_long	data;
433
434	__asm __volatile("movq %%cr2,%0" : "=r" (data));
435	return (data);
436}
437
438static __inline void
439load_cr3(u_long data)
440{
441
442	__asm __volatile("movq %0,%%cr3" : : "r" (data) : "memory");
443}
444
445static __inline u_long
446rcr3(void)
447{
448	u_long	data;
449
450	__asm __volatile("movq %%cr3,%0" : "=r" (data));
451	return (data);
452}
453
454static __inline void
455load_cr4(u_long data)
456{
457	__asm __volatile("movq %0,%%cr4" : : "r" (data));
458}
459
460static __inline u_long
461rcr4(void)
462{
463	u_long	data;
464
465	__asm __volatile("movq %%cr4,%0" : "=r" (data));
466	return (data);
467}
468
469/*
470 * Global TLB flush (except for thise for pages marked PG_G)
471 */
472static __inline void
473invltlb(void)
474{
475
476	load_cr3(rcr3());
477}
478
479/*
480 * TLB flush for an individual page (even if it has PG_G).
481 * Only works on 486+ CPUs (i386 does not have PG_G).
482 */
483static __inline void
484invlpg(u_long addr)
485{
486
487	__asm __volatile("invlpg %0" : : "m" (*(char *)addr) : "memory");
488}
489
490static __inline u_int
491rfs(void)
492{
493	u_int sel;
494	__asm __volatile("movl %%fs,%0" : "=rm" (sel));
495	return (sel);
496}
497
498static __inline u_int
499rgs(void)
500{
501	u_int sel;
502	__asm __volatile("movl %%gs,%0" : "=rm" (sel));
503	return (sel);
504}
505
506static __inline void
507load_ds(u_int sel)
508{
509	__asm __volatile("movl %0,%%ds" : : "rm" (sel));
510}
511
512static __inline void
513load_es(u_int sel)
514{
515	__asm __volatile("movl %0,%%es" : : "rm" (sel));
516}
517
518#ifdef _KERNEL
519/* This is defined in <machine/specialreg.h> but is too painful to get to */
520#ifndef	MSR_FSBASE
521#define	MSR_FSBASE	0xc0000100
522#endif
523static __inline void
524load_fs(u_int sel)
525{
526	register u_int32_t fsbase __asm("ecx");
527
528	/* Preserve the fsbase value across the selector load */
529	fsbase = MSR_FSBASE;
530        __asm __volatile("rdmsr; movl %0,%%fs; wrmsr"
531            : : "rm" (sel), "c" (fsbase) : "eax", "edx");
532}
533
534#ifndef	MSR_GSBASE
535#define	MSR_GSBASE	0xc0000101
536#endif
537static __inline void
538load_gs(u_int sel)
539{
540	register u_int32_t gsbase __asm("ecx");
541
542	/*
543	 * Preserve the gsbase value across the selector load.
544	 * Note that we have to disable interrupts because the gsbase
545	 * being trashed happens to be the kernel gsbase at the time.
546	 */
547	gsbase = MSR_GSBASE;
548        __asm __volatile("pushfq; cli; rdmsr; movl %0,%%gs; wrmsr; popfq"
549            : : "rm" (sel), "c" (gsbase) : "eax", "edx");
550}
551#else
552/* Usable by userland */
553static __inline void
554load_fs(u_int sel)
555{
556	__asm __volatile("movl %0,%%fs" : : "rm" (sel));
557}
558
559static __inline void
560load_gs(u_int sel)
561{
562	__asm __volatile("movl %0,%%gs" : : "rm" (sel));
563}
564#endif
565
566/* void lidt(struct region_descriptor *addr); */
567static __inline void
568lidt(struct region_descriptor *addr)
569{
570	__asm __volatile("lidt (%0)" : : "r" (addr));
571}
572
573/* void lldt(u_short sel); */
574static __inline void
575lldt(u_short sel)
576{
577	__asm __volatile("lldt %0" : : "r" (sel));
578}
579
580/* void ltr(u_short sel); */
581static __inline void
582ltr(u_short sel)
583{
584	__asm __volatile("ltr %0" : : "r" (sel));
585}
586
587static __inline u_int64_t
588rdr0(void)
589{
590	u_int64_t data;
591	__asm __volatile("movq %%dr0,%0" : "=r" (data));
592	return (data);
593}
594
595static __inline void
596load_dr0(u_int64_t dr0)
597{
598	__asm __volatile("movq %0,%%dr0" : : "r" (dr0));
599}
600
601static __inline u_int64_t
602rdr1(void)
603{
604	u_int64_t data;
605	__asm __volatile("movq %%dr1,%0" : "=r" (data));
606	return (data);
607}
608
609static __inline void
610load_dr1(u_int64_t dr1)
611{
612	__asm __volatile("movq %0,%%dr1" : : "r" (dr1));
613}
614
615static __inline u_int64_t
616rdr2(void)
617{
618	u_int64_t data;
619	__asm __volatile("movq %%dr2,%0" : "=r" (data));
620	return (data);
621}
622
623static __inline void
624load_dr2(u_int64_t dr2)
625{
626	__asm __volatile("movq %0,%%dr2" : : "r" (dr2));
627}
628
629static __inline u_int64_t
630rdr3(void)
631{
632	u_int64_t data;
633	__asm __volatile("movq %%dr3,%0" : "=r" (data));
634	return (data);
635}
636
637static __inline void
638load_dr3(u_int64_t dr3)
639{
640	__asm __volatile("movq %0,%%dr3" : : "r" (dr3));
641}
642
643static __inline u_int64_t
644rdr4(void)
645{
646	u_int64_t data;
647	__asm __volatile("movq %%dr4,%0" : "=r" (data));
648	return (data);
649}
650
651static __inline void
652load_dr4(u_int64_t dr4)
653{
654	__asm __volatile("movq %0,%%dr4" : : "r" (dr4));
655}
656
657static __inline u_int64_t
658rdr5(void)
659{
660	u_int64_t data;
661	__asm __volatile("movq %%dr5,%0" : "=r" (data));
662	return (data);
663}
664
665static __inline void
666load_dr5(u_int64_t dr5)
667{
668	__asm __volatile("movq %0,%%dr5" : : "r" (dr5));
669}
670
671static __inline u_int64_t
672rdr6(void)
673{
674	u_int64_t data;
675	__asm __volatile("movq %%dr6,%0" : "=r" (data));
676	return (data);
677}
678
679static __inline void
680load_dr6(u_int64_t dr6)
681{
682	__asm __volatile("movq %0,%%dr6" : : "r" (dr6));
683}
684
685static __inline u_int64_t
686rdr7(void)
687{
688	u_int64_t data;
689	__asm __volatile("movq %%dr7,%0" : "=r" (data));
690	return (data);
691}
692
693static __inline void
694load_dr7(u_int64_t dr7)
695{
696	__asm __volatile("movq %0,%%dr7" : : "r" (dr7));
697}
698
699static __inline register_t
700intr_disable(void)
701{
702	register_t rflags;
703
704	rflags = read_rflags();
705	disable_intr();
706	return (rflags);
707}
708
709static __inline void
710intr_restore(register_t rflags)
711{
712	write_rflags(rflags);
713}
714
715#else /* !__GNUC__ */
716
717int	breakpoint(void);
718u_int	bsfl(u_int mask);
719u_int	bsrl(u_int mask);
720void	cpu_invlpg(u_long addr);
721void	cpu_invlpg_range(u_long start, u_long end);
722void	disable_intr(void);
723void	do_cpuid(u_int ax, u_int *p);
724void	enable_intr(void);
725void	halt(void);
726u_char	inb(u_int port);
727u_int	inl(u_int port);
728void	insb(u_int port, void *addr, size_t cnt);
729void	insl(u_int port, void *addr, size_t cnt);
730void	insw(u_int port, void *addr, size_t cnt);
731void	invd(void);
732void	invlpg(u_int addr);
733void	invlpg_range(u_int start, u_int end);
734void	invltlb(void);
735u_short	inw(u_int port);
736void	load_cr0(u_int cr0);
737void	load_cr3(u_int cr3);
738void	load_cr4(u_int cr4);
739void	load_fs(u_int sel);
740void	load_gs(u_int sel);
741struct region_descriptor;
742void	lidt(struct region_descriptor *addr);
743void	lldt(u_short sel);
744void	ltr(u_short sel);
745void	outb(u_int port, u_char data);
746void	outl(u_int port, u_int data);
747void	outsb(u_int port, void *addr, size_t cnt);
748void	outsl(u_int port, void *addr, size_t cnt);
749void	outsw(u_int port, void *addr, size_t cnt);
750void	outw(u_int port, u_short data);
751void	ia32_pause(void);
752u_int	rcr0(void);
753u_int	rcr2(void);
754u_int	rcr3(void);
755u_int	rcr4(void);
756u_int	rfs(void);
757u_int	rgs(void);
758u_int64_t rdmsr(u_int msr);
759u_int64_t rdpmc(u_int pmc);
760u_int64_t rdtsc(void);
761u_int	read_rflags(void);
762void	wbinvd(void);
763void	write_rflags(u_int rf);
764void	wrmsr(u_int msr, u_int64_t newval);
765u_int64_t	rdr0(void);
766void	load_dr0(u_int64_t dr0);
767u_int64_t	rdr1(void);
768void	load_dr1(u_int64_t dr1);
769u_int64_t	rdr2(void);
770void	load_dr2(u_int64_t dr2);
771u_int64_t	rdr3(void);
772void	load_dr3(u_int64_t dr3);
773u_int64_t	rdr4(void);
774void	load_dr4(u_int64_t dr4);
775u_int64_t	rdr5(void);
776void	load_dr5(u_int64_t dr5);
777u_int64_t	rdr6(void);
778void	load_dr6(u_int64_t dr6);
779u_int64_t	rdr7(void);
780void	load_dr7(u_int64_t dr7);
781register_t	intr_disable(void);
782void	intr_restore(register_t rf);
783
784#endif	/* __GNUC__ */
785
786void	reset_dbregs(void);
787
788__END_DECLS
789
790#endif /* !_MACHINE_CPUFUNC_H_ */
791