cpufunc.h revision 12592
123925Sgibbs/*-
223925Sgibbs * Copyright (c) 1993 The Regents of the University of California.
323925Sgibbs * All rights reserved.
455581Sgibbs *
523925Sgibbs * Redistribution and use in source and binary forms, with or without
623925Sgibbs * modification, are permitted provided that the following conditions
723925Sgibbs * are met:
823925Sgibbs * 1. Redistributions of source code must retain the above copyright
923925Sgibbs *    notice, this list of conditions and the following disclaimer.
1023925Sgibbs * 2. Redistributions in binary form must reproduce the above copyright
1126997Sgibbs *    notice, this list of conditions and the following disclaimer in the
1254211Sgibbs *    documentation and/or other materials provided with the distribution.
1339220Sgibbs * 3. All advertising materials mentioning features or use of this software
1423925Sgibbs *    must display the following acknowledgement:
1523925Sgibbs *	This product includes software developed by the University of
1654211Sgibbs *	California, Berkeley and its contributors.
1763457Sgibbs * 4. Neither the name of the University nor the names of its contributors
1826997Sgibbs *    may be used to endorse or promote products derived from this software
1923925Sgibbs *    without specific prior written permission.
2023925Sgibbs *
2123925Sgibbs * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2223925Sgibbs * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2323925Sgibbs * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2423925Sgibbs * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2523925Sgibbs * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2623925Sgibbs * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2723925Sgibbs * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2823925Sgibbs * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2923925Sgibbs * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3023925Sgibbs * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3165942Sgibbs * SUCH DAMAGE.
3265942Sgibbs *
3350477Speter *	$Id: cpufunc.h,v 1.41 1995/10/05 10:32:47 phk Exp $
3423925Sgibbs */
3523925Sgibbs
3623925Sgibbs/*
3723925Sgibbs * Functions to provide access to special i386 instructions.
3823925Sgibbs */
3923925Sgibbs
4023925Sgibbs#ifndef _MACHINE_CPUFUNC_H_
4123925Sgibbs#define	_MACHINE_CPUFUNC_H_
4223925Sgibbs
4323925Sgibbs#include <sys/cdefs.h>
4423925Sgibbs#include <sys/types.h>
4523925Sgibbs
4623925Sgibbs#include <machine/spl.h>	/* XXX belongs elsewhere */
4723925Sgibbs
4823925Sgibbs#ifdef	__GNUC__
4923925Sgibbs
5023925Sgibbs#ifdef BDE_DEBUGGER
5123925Sgibbsextern int	bdb_exists;
5223925Sgibbs
5323925Sgibbsstatic __inline int
5423925Sgibbsbdb(void)
5523925Sgibbs{
5623925Sgibbs	if (!bdb_exists)
5723925Sgibbs		return (0);
5823925Sgibbs	__asm __volatile("int $3");
5923925Sgibbs	return (1);
6023925Sgibbs}
6123925Sgibbs#endif /* BDE_DEBUGGER */
6223925Sgibbs
6323925Sgibbsstatic __inline void
6423925Sgibbsdisable_intr(void)
6523925Sgibbs{
6623925Sgibbs	__asm __volatile("cli" : : : "memory");
6723925Sgibbs}
6823925Sgibbs
6923925Sgibbsstatic __inline void
7023925Sgibbsenable_intr(void)
7123925Sgibbs{
7223925Sgibbs	__asm __volatile("sti");
7323925Sgibbs}
7423925Sgibbs
7523925Sgibbs#define	HAVE_INLINE_FFS
7623925Sgibbs
7723925Sgibbsstatic __inline int
7823925Sgibbsffs(int mask)
7923925Sgibbs{
8023925Sgibbs	int	result;
8123925Sgibbs	/*
8223925Sgibbs	 * bsfl turns out to be not all that slow on 486's.  It can beaten
8323925Sgibbs	 * using a binary search to reduce to 4 bits and then a table lookup,
8423925Sgibbs	 * but only if the code is inlined and in the cache, and the code
8523925Sgibbs	 * is quite large so inlining it probably busts the cache.
8623925Sgibbs	 *
8723925Sgibbs	 * Note that gcc-2's builtin ffs would be used if we didn't declare
8823925Sgibbs	 * this inline or turn off the builtin.  The builtin is faster but
8923925Sgibbs	 * broken in gcc-2.4.5 and slower but working in gcc-2.5 and 2.6.
9023925Sgibbs	 */
9123925Sgibbs	__asm __volatile("testl %0,%0; je 1f; bsfl %0,%0; incl %0; 1:"
9223925Sgibbs			 : "=r" (result) : "0" (mask));
9323925Sgibbs	return (result);
9423925Sgibbs}
9523925Sgibbs
9623925Sgibbs#if __GNUC__ < 2
9723925Sgibbs
9823925Sgibbs#define	inb(port)		inbv(port)
9923925Sgibbs#define	outb(port, data)	outbv(port, data)
10023925Sgibbs
10123925Sgibbs#else /* __GNUC >= 2 */
10223925Sgibbs
10323925Sgibbs/*
10423925Sgibbs * The following complications are to get around gcc not having a
10523925Sgibbs * constraint letter for the range 0..255.  We still put "d" in the
10623925Sgibbs * constraint because "i" isn't a valid constraint when the port
10723925Sgibbs * isn't constant.  This only matters for -O0 because otherwise
10823925Sgibbs * the non-working version gets optimized away.
10923925Sgibbs *
11023925Sgibbs * Use an expression-statement instead of a conditional expression
11123925Sgibbs * because gcc-2.6.0 would promote the operands of the conditional
11223925Sgibbs * and produce poor code for "if ((inb(var) & const1) == const2)".
11323925Sgibbs */
11423925Sgibbs#define	inb(port)	({						\
11523925Sgibbs	u_char	_data;							\
11623925Sgibbs	if (__builtin_constant_p((int) (port)) && (port) < 256ul)	\
11723925Sgibbs		_data = inbc(port);					\
11823925Sgibbs	else								\
11923925Sgibbs		_data = inbv(port);					\
12023925Sgibbs	_data; })
12123925Sgibbs
12223925Sgibbs#define	outb(port, data) \
12323925Sgibbs	(__builtin_constant_p((int) (port)) && (port) < 256ul \
12423925Sgibbs	 ? outbc(port, data) : outbv(port, data))
12523925Sgibbs
12623925Sgibbsstatic __inline u_char
12723925Sgibbsinbc(u_int port)
12823925Sgibbs{
12923925Sgibbs	u_char	data;
13023925Sgibbs
13123925Sgibbs	__asm __volatile("inb %1,%0" : "=a" (data) : "id" ((u_short)(port)));
13223925Sgibbs	return (data);
13323925Sgibbs}
13423925Sgibbs
13523925Sgibbsstatic __inline void
13623925Sgibbsoutbc(u_int port, u_char data)
13723925Sgibbs{
13823925Sgibbs	__asm __volatile("outb %0,%1" : : "a" (data), "id" ((u_short)(port)));
13923925Sgibbs}
14023925Sgibbs
14123925Sgibbs#endif /* __GNUC <= 2 */
14223925Sgibbs
14323925Sgibbsstatic __inline u_char
14423925Sgibbsinbv(u_int port)
14523925Sgibbs{
14623925Sgibbs	u_char	data;
14723925Sgibbs	/*
14823925Sgibbs	 * We use %%dx and not %1 here because i/o is done at %dx and not at
14923925Sgibbs	 * %edx, while gcc generates inferior code (movw instead of movl)
15023925Sgibbs	 * if we tell it to load (u_short) port.
15123925Sgibbs	 */
15223925Sgibbs	__asm __volatile("inb %%dx,%0" : "=a" (data) : "d" (port));
15323925Sgibbs	return (data);
15423925Sgibbs}
15523925Sgibbs
15623925Sgibbsstatic __inline u_long
15723925Sgibbsinl(u_int port)
15823925Sgibbs{
15923925Sgibbs	u_long	data;
16023925Sgibbs
16155581Sgibbs	__asm __volatile("inl %%dx,%0" : "=a" (data) : "d" (port));
16255581Sgibbs	return (data);
16323925Sgibbs}
16455581Sgibbs
16523925Sgibbsstatic __inline void
16623925Sgibbsinsb(u_int port, void *addr, size_t cnt)
16723925Sgibbs{
16823925Sgibbs	__asm __volatile("cld; rep; insb"
16923925Sgibbs			 : : "d" (port), "D" (addr), "c" (cnt)
17023925Sgibbs			 : "di", "cx", "memory");
17123925Sgibbs}
17223925Sgibbs
17323925Sgibbsstatic __inline void
17423925Sgibbsinsw(u_int port, void *addr, size_t cnt)
17523925Sgibbs{
17623925Sgibbs	__asm __volatile("cld; rep; insw"
17763457Sgibbs			 : : "d" (port), "D" (addr), "c" (cnt)
17863457Sgibbs			 : "di", "cx", "memory");
17923925Sgibbs}
18039220Sgibbs
18139220Sgibbsstatic __inline void
18239220Sgibbsinsl(u_int port, void *addr, size_t cnt)
18339220Sgibbs{
18439220Sgibbs	__asm __volatile("cld; rep; insl"
18539220Sgibbs			 : : "d" (port), "D" (addr), "c" (cnt)
18639220Sgibbs			 : "di", "cx", "memory");
18723925Sgibbs}
18823925Sgibbs
18923925Sgibbsstatic __inline u_short
19023925Sgibbsinw(u_int port)
19123925Sgibbs{
19223925Sgibbs	u_short	data;
19323925Sgibbs
19423925Sgibbs	__asm __volatile("inw %%dx,%0" : "=a" (data) : "d" (port));
19523925Sgibbs	return (data);
19623925Sgibbs}
19723925Sgibbs
19823925Sgibbsstatic __inline unsigned
19923925Sgibbsloadandclear(u_int *addr)
20023925Sgibbs{
20123925Sgibbs	u_int	result;
20223925Sgibbs
20323925Sgibbs	__asm __volatile("xorl %0,%0; xchgl %1,%0"
20423925Sgibbs			 : "=&r" (result) : "m" (*addr));
20523925Sgibbs	return (result);
20623925Sgibbs}
20723925Sgibbs
20823925Sgibbsstatic __inline void
20923925Sgibbsoutbv(u_int port, u_char data)
21023925Sgibbs{
21123925Sgibbs	u_char	al;
21223925Sgibbs	/*
21323925Sgibbs	 * Use an unnecessary assignment to help gcc's register allocator.
21423925Sgibbs	 * This make a large difference for gcc-1.40 and a tiny difference
21523925Sgibbs	 * for gcc-2.6.0.  For gcc-1.40, al had to be ``asm("ax")'' for
21623925Sgibbs	 * best results.  gcc-2.6.0 can't handle this.
21723925Sgibbs	 */
21855581Sgibbs	al = data;
21955581Sgibbs	__asm __volatile("outb %0,%%dx" : : "a" (al), "d" (port));
22055581Sgibbs}
22155581Sgibbs
22255581Sgibbsstatic __inline void
22355581Sgibbsoutl(u_int port, u_long data)
22455581Sgibbs{
22555581Sgibbs	/*
22655581Sgibbs	 * outl() and outw() aren't used much so we haven't looked at
22755581Sgibbs	 * possible micro-optimizations such as the unnecessary
22855581Sgibbs	 * assignment for them.
22955581Sgibbs	 */
23055581Sgibbs	__asm __volatile("outl %0,%%dx" : : "a" (data), "d" (port));
23155581Sgibbs}
23255581Sgibbs
23355581Sgibbsstatic __inline void
23455581Sgibbsoutsb(u_int port, void *addr, size_t cnt)
23555581Sgibbs{
23655581Sgibbs	__asm __volatile("cld; rep; outsb"
23755581Sgibbs			 : : "d" (port), "S" (addr), "c" (cnt)
23855581Sgibbs			 : "si", "cx");
23955581Sgibbs}
24023925Sgibbs
24123925Sgibbsstatic __inline void
24223925Sgibbsoutsw(u_int port, void *addr, size_t cnt)
24323925Sgibbs{
24423925Sgibbs	__asm __volatile("cld; rep; outsw"
24523925Sgibbs			 : : "d" (port), "S" (addr), "c" (cnt)
24623925Sgibbs			 : "si", "cx");
24723925Sgibbs}
24823925Sgibbs
24923925Sgibbsstatic __inline void
25023925Sgibbsoutsl(u_int port, void *addr, size_t cnt)
25123925Sgibbs{
25223925Sgibbs	__asm __volatile("cld; rep; outsl"
25323925Sgibbs			 : : "d" (port), "S" (addr), "c" (cnt)
25423925Sgibbs			 : "si", "cx");
25523925Sgibbs}
25623925Sgibbs
25723925Sgibbsstatic __inline void
25823925Sgibbsoutw(u_int port, u_short data)
25923925Sgibbs{
26023925Sgibbs	__asm __volatile("outw %0,%%dx" : : "a" (data), "d" (port));
26123925Sgibbs}
26239220Sgibbs
26339220Sgibbsstatic __inline void
26439220Sgibbspmap_update(void)
26539220Sgibbs{
26639220Sgibbs	u_long	temp;
26739220Sgibbs	/*
26839220Sgibbs	 * This should be implemented as load_cr3(rcr3()) when load_cr3()
26939220Sgibbs	 * is inlined.
27039220Sgibbs	 */
27123925Sgibbs	__asm __volatile("movl %%cr3, %0; movl %0, %%cr3" : "=r" (temp)
27223925Sgibbs			 : : "memory");
27323925Sgibbs}
27423925Sgibbs
27523925Sgibbsstatic __inline u_long
27623925Sgibbsrcr2(void)
27723925Sgibbs{
27823925Sgibbs	u_long	data;
27923925Sgibbs
28023925Sgibbs	__asm __volatile("movl %%cr2,%0" : "=r" (data));
28123925Sgibbs	return (data);
28223925Sgibbs}
28323925Sgibbs
28423925Sgibbsstatic __inline u_long
28523925Sgibbsread_eflags(void)
28623925Sgibbs{
28723925Sgibbs	u_long	ef;
28823925Sgibbs
28923925Sgibbs	__asm __volatile("pushfl; popl %0" : "=r" (ef));
29023925Sgibbs	return (ef);
29123925Sgibbs}
29223925Sgibbs
29323925Sgibbsstatic __inline void
29423925Sgibbswrite_eflags(u_long ef)
29523925Sgibbs{
29623925Sgibbs	__asm __volatile("pushl %0; popfl" : : "r" (ef));
29723925Sgibbs}
29823925Sgibbs
29923925Sgibbs#else /* !__GNUC__ */
30023925Sgibbs
30123925Sgibbsint	bdb		__P((void));
30223925Sgibbsvoid	disable_intr	__P((void));
30323925Sgibbsvoid	enable_intr	__P((void));
30423925Sgibbsu_char	inb		__P((u_int port));
30523925Sgibbsu_long	inl		__P((u_int port));
30623925Sgibbsvoid	insb		__P((u_int port, void *addr, size_t cnt));
30723925Sgibbsvoid	insl		__P((u_int port, void *addr, size_t cnt));
30823925Sgibbsvoid	insw		__P((u_int port, void *addr, size_t cnt));
30923925Sgibbsu_short	inw		__P((u_int port));
31023925Sgibbsu_int	loadandclear	__P((u_int *addr));
31123925Sgibbsvoid	outb		__P((u_int port, u_char data));
31263944Sgibbsvoid	outl		__P((u_int port, u_long data));
31339220Sgibbsvoid	outsb		__P((u_int port, void *addr, size_t cnt));
31423925Sgibbsvoid	outsl		__P((u_int port, void *addr, size_t cnt));
31523925Sgibbsvoid	outsw		__P((u_int port, void *addr, size_t cnt));
31623925Sgibbsvoid	outw		__P((u_int port, u_short data));
31723925Sgibbsvoid	pmap_update	__P((void));
31823925Sgibbsu_long	read_eflags	__P((void));
31923925Sgibbsu_long	rcr2		__P((void));
32023925Sgibbsvoid	write_eflags	__P((u_long ef));
32123925Sgibbs
32223925Sgibbs#endif	/* __GNUC__ */
32323925Sgibbs
32423925Sgibbs/*
32523925Sgibbs * XXX the following declarations document garbage in support.s.
32623925Sgibbs * bcopy[bwx]() was used by pccons but isn't used now.
32723925Sgibbs */
32839220Sgibbsvoid	bcopyb		__P((const void *from, void *to, size_t len));
32923925Sgibbsvoid	bcopyw		__P((const void *from, void *to, size_t len));
33039220Sgibbsvoid	bcopyx		__P((const void *from, void *to, size_t len,
33123925Sgibbs			     int stride));
33223925Sgibbs
33339220Sgibbs#if 0
33439220Sgibbs/*
33523925Sgibbs * These functions in support.s are declared elsewhere.
33623925Sgibbs */
33723925Sgibbsvoid	bcopy		__P((const void *from, void *to, size_t len));
33823925Sgibbsvoid	blkclr		__P((void *buf, size_t len));
33923925Sgibbsvoid	bzero		__P((void *buf, size_t len));
34023925Sgibbsint	copyin		__P((void *udaddr, void *kaddr, size_t len));
34123925Sgibbsint	copyinstr	__P((void *udaddr, void *kaddr, size_t len,
34223925Sgibbs			     size_t *lencopied));
34323925Sgibbsint	copyout		__P((void *kaddr, void *udaddr, size_t len));
34423925Sgibbsint	copystr		__P((void *kfaddr, void *kdaddr, size_t len,
34523925Sgibbs			     size_t *lencopied));
34623925Sgibbsint	fubyte		__P((void *base));
34723925Sgibbsint	fuswintr	__P((void *base));
34823925Sgibbsint	fuibyte		__P((void *base));
34939220Sgibbsint	fuword		__P((void *base));
35023925Sgibbsstruct	region_descriptor;
35123925Sgibbsvoid	lgdt		__P((struct region_descriptor *rdp));
35223925Sgibbsvoid	lidt		__P((struct region_descriptor *rdp));
35323925Sgibbsvoid	lldt		__P((u_short sel));
35423925Sgibbs/*
35523925Sgibbs * longjmp() and setjmp() are only used by ddb.  They probably shouldn't
35623925Sgibbs * shouldn't be supported in the kernel.
35723925Sgibbs */
35823925Sgibbs#include <setjmp.h>
35923925Sgibbsvoid	longjmp		__P((jmp_buf jb, int rv));
36023925Sgibbsvoid	ovbcopy		__P((const void *from, void *to, size_t len);
36123925Sgibbsint	setjmp		__P((jmp_buf jb));
36223925Sgibbsstruct soft_segment_descriptor;
36323925Sgibbsunion descriptor;
36423925Sgibbsint	ssdtosd		__P((struct soft_segment_descriptor *ssdp,
36523925Sgibbs			     union descriptor *sdp));
36623925Sgibbsint	subyte		__P((void *base, int byte));
36723925Sgibbsint	suibyte		__P((void *base, int byte));
36823925Sgibbsint	suswintr	__P((void *base, int word));
36923925Sgibbsint	suword		__P((void *base, int word));
37023925Sgibbs
37123925Sgibbs/*
37223925Sgibbs * These functions in support.s are declared elsewhere, but never used.
37323925Sgibbs * A silly amount of effort went into copyoutstr().  It's not worth
37423925Sgibbs * maintaining, since the string length is usually known so copyout
37523925Sgibbs * works better, or is easy to find so copyout() can be used.
37623925Sgibbs */
37723925Sgibbsint	copyoutstr	__P((void *kaddr, void *udaddr, size_t len,
37823925Sgibbs			     size_t *lencopied));
37923925Sgibbsint	fuiword		__P((void *base));
38023925Sgibbsint	suiword		__P((void *base, int word));
38123925Sgibbs
38223925Sgibbs/*
38323925Sgibbs * These functions in support.s are also in libkern.a and are declared in
38423925Sgibbs * libkern.h.
38523925Sgibbs * ffs() is built in to gcc-2 and was buggy in gcc-2.4.5 so we may may the
38623925Sgibbs * buggy version if we don't replace it by an inline.
38723925Sgibbs */
38823925Sgibbsint	bcmp		__P((const void *b1, const void *b2, size_t length));
38923925Sgibbsint	ffs		__P((int mask));
39023925Sgibbs#endif /* 0 */
39123925Sgibbs
39223925Sgibbs/*
39323925Sgibbs * These variables and functions in support.s are used.
39423925Sgibbs */
39523925Sgibbsextern u_int atdevbase;	/* offset in virtual memory of ISA io mem */
39623925Sgibbs
39723925Sgibbsvoid	filli		__P((int pat, void *base, size_t cnt));
39823925Sgibbsvoid	fillw		__P((int /*u_short*/ pat, void *base, size_t cnt));
39923925Sgibbsint	fusword		__P((void *base));
40023925Sgibbsvoid	load_cr0	__P((u_long cr0));
40123925Sgibbsvoid	load_cr3	__P((u_long cr3));
40223925Sgibbsvoid	ltr		__P((u_short sel));
40323925Sgibbsu_int	rcr0		__P((void));
40423925Sgibbsu_long	rcr3		__P((void));
40523925Sgibbsint	rtcin		__P((int val));
40623925Sgibbs
40723925Sgibbs/*
40823925Sgibbs * These functions are NOT in support.s and should be declared elsewhere.
40923925Sgibbs */
41023925Sgibbsvoid	Debugger	__P((const char *msg));
41123925Sgibbsu_long	kvtop		__P((void *addr));
41223925Sgibbstypedef void alias_for_inthand_t __P((u_int cs, u_int ef, u_int esp,
41339220Sgibbs				      u_int ss));
41423925Sgibbsvoid	setidt		__P((int idx, alias_for_inthand_t *func, int typ,
41523925Sgibbs			     int dpl));
41623925Sgibbs
41723925Sgibbs#endif /* !_MACHINE_CPUFUNC_H_ */
41823925Sgibbs