cpufunc.h revision 12592
1/*-
2 * Copyright (c) 1993 The Regents of the University of California.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 *    must display the following acknowledgement:
15 *	This product includes software developed by the University of
16 *	California, Berkeley and its contributors.
17 * 4. Neither the name of the University nor the names of its contributors
18 *    may be used to endorse or promote products derived from this software
19 *    without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 *
33 *	$Id: cpufunc.h,v 1.41 1995/10/05 10:32:47 phk Exp $
34 */
35
36/*
37 * Functions to provide access to special i386 instructions.
38 */
39
40#ifndef _MACHINE_CPUFUNC_H_
41#define	_MACHINE_CPUFUNC_H_
42
43#include <sys/cdefs.h>
44#include <sys/types.h>
45
46#include <machine/spl.h>	/* XXX belongs elsewhere */
47
48#ifdef	__GNUC__
49
50#ifdef BDE_DEBUGGER
51extern int	bdb_exists;
52
53static __inline int
54bdb(void)
55{
56	if (!bdb_exists)
57		return (0);
58	__asm __volatile("int $3");
59	return (1);
60}
61#endif /* BDE_DEBUGGER */
62
63static __inline void
64disable_intr(void)
65{
66	__asm __volatile("cli" : : : "memory");
67}
68
69static __inline void
70enable_intr(void)
71{
72	__asm __volatile("sti");
73}
74
75#define	HAVE_INLINE_FFS
76
77static __inline int
78ffs(int mask)
79{
80	int	result;
81	/*
82	 * bsfl turns out to be not all that slow on 486's.  It can beaten
83	 * using a binary search to reduce to 4 bits and then a table lookup,
84	 * but only if the code is inlined and in the cache, and the code
85	 * is quite large so inlining it probably busts the cache.
86	 *
87	 * Note that gcc-2's builtin ffs would be used if we didn't declare
88	 * this inline or turn off the builtin.  The builtin is faster but
89	 * broken in gcc-2.4.5 and slower but working in gcc-2.5 and 2.6.
90	 */
91	__asm __volatile("testl %0,%0; je 1f; bsfl %0,%0; incl %0; 1:"
92			 : "=r" (result) : "0" (mask));
93	return (result);
94}
95
96#if __GNUC__ < 2
97
98#define	inb(port)		inbv(port)
99#define	outb(port, data)	outbv(port, data)
100
101#else /* __GNUC >= 2 */
102
103/*
104 * The following complications are to get around gcc not having a
105 * constraint letter for the range 0..255.  We still put "d" in the
106 * constraint because "i" isn't a valid constraint when the port
107 * isn't constant.  This only matters for -O0 because otherwise
108 * the non-working version gets optimized away.
109 *
110 * Use an expression-statement instead of a conditional expression
111 * because gcc-2.6.0 would promote the operands of the conditional
112 * and produce poor code for "if ((inb(var) & const1) == const2)".
113 */
114#define	inb(port)	({						\
115	u_char	_data;							\
116	if (__builtin_constant_p((int) (port)) && (port) < 256ul)	\
117		_data = inbc(port);					\
118	else								\
119		_data = inbv(port);					\
120	_data; })
121
122#define	outb(port, data) \
123	(__builtin_constant_p((int) (port)) && (port) < 256ul \
124	 ? outbc(port, data) : outbv(port, data))
125
126static __inline u_char
127inbc(u_int port)
128{
129	u_char	data;
130
131	__asm __volatile("inb %1,%0" : "=a" (data) : "id" ((u_short)(port)));
132	return (data);
133}
134
135static __inline void
136outbc(u_int port, u_char data)
137{
138	__asm __volatile("outb %0,%1" : : "a" (data), "id" ((u_short)(port)));
139}
140
141#endif /* __GNUC <= 2 */
142
143static __inline u_char
144inbv(u_int port)
145{
146	u_char	data;
147	/*
148	 * We use %%dx and not %1 here because i/o is done at %dx and not at
149	 * %edx, while gcc generates inferior code (movw instead of movl)
150	 * if we tell it to load (u_short) port.
151	 */
152	__asm __volatile("inb %%dx,%0" : "=a" (data) : "d" (port));
153	return (data);
154}
155
156static __inline u_long
157inl(u_int port)
158{
159	u_long	data;
160
161	__asm __volatile("inl %%dx,%0" : "=a" (data) : "d" (port));
162	return (data);
163}
164
165static __inline void
166insb(u_int port, void *addr, size_t cnt)
167{
168	__asm __volatile("cld; rep; insb"
169			 : : "d" (port), "D" (addr), "c" (cnt)
170			 : "di", "cx", "memory");
171}
172
173static __inline void
174insw(u_int port, void *addr, size_t cnt)
175{
176	__asm __volatile("cld; rep; insw"
177			 : : "d" (port), "D" (addr), "c" (cnt)
178			 : "di", "cx", "memory");
179}
180
181static __inline void
182insl(u_int port, void *addr, size_t cnt)
183{
184	__asm __volatile("cld; rep; insl"
185			 : : "d" (port), "D" (addr), "c" (cnt)
186			 : "di", "cx", "memory");
187}
188
189static __inline u_short
190inw(u_int port)
191{
192	u_short	data;
193
194	__asm __volatile("inw %%dx,%0" : "=a" (data) : "d" (port));
195	return (data);
196}
197
198static __inline unsigned
199loadandclear(u_int *addr)
200{
201	u_int	result;
202
203	__asm __volatile("xorl %0,%0; xchgl %1,%0"
204			 : "=&r" (result) : "m" (*addr));
205	return (result);
206}
207
208static __inline void
209outbv(u_int port, u_char data)
210{
211	u_char	al;
212	/*
213	 * Use an unnecessary assignment to help gcc's register allocator.
214	 * This make a large difference for gcc-1.40 and a tiny difference
215	 * for gcc-2.6.0.  For gcc-1.40, al had to be ``asm("ax")'' for
216	 * best results.  gcc-2.6.0 can't handle this.
217	 */
218	al = data;
219	__asm __volatile("outb %0,%%dx" : : "a" (al), "d" (port));
220}
221
222static __inline void
223outl(u_int port, u_long data)
224{
225	/*
226	 * outl() and outw() aren't used much so we haven't looked at
227	 * possible micro-optimizations such as the unnecessary
228	 * assignment for them.
229	 */
230	__asm __volatile("outl %0,%%dx" : : "a" (data), "d" (port));
231}
232
233static __inline void
234outsb(u_int port, void *addr, size_t cnt)
235{
236	__asm __volatile("cld; rep; outsb"
237			 : : "d" (port), "S" (addr), "c" (cnt)
238			 : "si", "cx");
239}
240
241static __inline void
242outsw(u_int port, void *addr, size_t cnt)
243{
244	__asm __volatile("cld; rep; outsw"
245			 : : "d" (port), "S" (addr), "c" (cnt)
246			 : "si", "cx");
247}
248
249static __inline void
250outsl(u_int port, void *addr, size_t cnt)
251{
252	__asm __volatile("cld; rep; outsl"
253			 : : "d" (port), "S" (addr), "c" (cnt)
254			 : "si", "cx");
255}
256
257static __inline void
258outw(u_int port, u_short data)
259{
260	__asm __volatile("outw %0,%%dx" : : "a" (data), "d" (port));
261}
262
263static __inline void
264pmap_update(void)
265{
266	u_long	temp;
267	/*
268	 * This should be implemented as load_cr3(rcr3()) when load_cr3()
269	 * is inlined.
270	 */
271	__asm __volatile("movl %%cr3, %0; movl %0, %%cr3" : "=r" (temp)
272			 : : "memory");
273}
274
275static __inline u_long
276rcr2(void)
277{
278	u_long	data;
279
280	__asm __volatile("movl %%cr2,%0" : "=r" (data));
281	return (data);
282}
283
284static __inline u_long
285read_eflags(void)
286{
287	u_long	ef;
288
289	__asm __volatile("pushfl; popl %0" : "=r" (ef));
290	return (ef);
291}
292
293static __inline void
294write_eflags(u_long ef)
295{
296	__asm __volatile("pushl %0; popfl" : : "r" (ef));
297}
298
299#else /* !__GNUC__ */
300
301int	bdb		__P((void));
302void	disable_intr	__P((void));
303void	enable_intr	__P((void));
304u_char	inb		__P((u_int port));
305u_long	inl		__P((u_int port));
306void	insb		__P((u_int port, void *addr, size_t cnt));
307void	insl		__P((u_int port, void *addr, size_t cnt));
308void	insw		__P((u_int port, void *addr, size_t cnt));
309u_short	inw		__P((u_int port));
310u_int	loadandclear	__P((u_int *addr));
311void	outb		__P((u_int port, u_char data));
312void	outl		__P((u_int port, u_long data));
313void	outsb		__P((u_int port, void *addr, size_t cnt));
314void	outsl		__P((u_int port, void *addr, size_t cnt));
315void	outsw		__P((u_int port, void *addr, size_t cnt));
316void	outw		__P((u_int port, u_short data));
317void	pmap_update	__P((void));
318u_long	read_eflags	__P((void));
319u_long	rcr2		__P((void));
320void	write_eflags	__P((u_long ef));
321
322#endif	/* __GNUC__ */
323
324/*
325 * XXX the following declarations document garbage in support.s.
326 * bcopy[bwx]() was used by pccons but isn't used now.
327 */
328void	bcopyb		__P((const void *from, void *to, size_t len));
329void	bcopyw		__P((const void *from, void *to, size_t len));
330void	bcopyx		__P((const void *from, void *to, size_t len,
331			     int stride));
332
333#if 0
334/*
335 * These functions in support.s are declared elsewhere.
336 */
337void	bcopy		__P((const void *from, void *to, size_t len));
338void	blkclr		__P((void *buf, size_t len));
339void	bzero		__P((void *buf, size_t len));
340int	copyin		__P((void *udaddr, void *kaddr, size_t len));
341int	copyinstr	__P((void *udaddr, void *kaddr, size_t len,
342			     size_t *lencopied));
343int	copyout		__P((void *kaddr, void *udaddr, size_t len));
344int	copystr		__P((void *kfaddr, void *kdaddr, size_t len,
345			     size_t *lencopied));
346int	fubyte		__P((void *base));
347int	fuswintr	__P((void *base));
348int	fuibyte		__P((void *base));
349int	fuword		__P((void *base));
350struct	region_descriptor;
351void	lgdt		__P((struct region_descriptor *rdp));
352void	lidt		__P((struct region_descriptor *rdp));
353void	lldt		__P((u_short sel));
354/*
355 * longjmp() and setjmp() are only used by ddb.  They probably shouldn't
356 * shouldn't be supported in the kernel.
357 */
358#include <setjmp.h>
359void	longjmp		__P((jmp_buf jb, int rv));
360void	ovbcopy		__P((const void *from, void *to, size_t len);
361int	setjmp		__P((jmp_buf jb));
362struct soft_segment_descriptor;
363union descriptor;
364int	ssdtosd		__P((struct soft_segment_descriptor *ssdp,
365			     union descriptor *sdp));
366int	subyte		__P((void *base, int byte));
367int	suibyte		__P((void *base, int byte));
368int	suswintr	__P((void *base, int word));
369int	suword		__P((void *base, int word));
370
371/*
372 * These functions in support.s are declared elsewhere, but never used.
373 * A silly amount of effort went into copyoutstr().  It's not worth
374 * maintaining, since the string length is usually known so copyout
375 * works better, or is easy to find so copyout() can be used.
376 */
377int	copyoutstr	__P((void *kaddr, void *udaddr, size_t len,
378			     size_t *lencopied));
379int	fuiword		__P((void *base));
380int	suiword		__P((void *base, int word));
381
382/*
383 * These functions in support.s are also in libkern.a and are declared in
384 * libkern.h.
385 * ffs() is built in to gcc-2 and was buggy in gcc-2.4.5 so we may may the
386 * buggy version if we don't replace it by an inline.
387 */
388int	bcmp		__P((const void *b1, const void *b2, size_t length));
389int	ffs		__P((int mask));
390#endif /* 0 */
391
392/*
393 * These variables and functions in support.s are used.
394 */
395extern u_int atdevbase;	/* offset in virtual memory of ISA io mem */
396
397void	filli		__P((int pat, void *base, size_t cnt));
398void	fillw		__P((int /*u_short*/ pat, void *base, size_t cnt));
399int	fusword		__P((void *base));
400void	load_cr0	__P((u_long cr0));
401void	load_cr3	__P((u_long cr3));
402void	ltr		__P((u_short sel));
403u_int	rcr0		__P((void));
404u_long	rcr3		__P((void));
405int	rtcin		__P((int val));
406
407/*
408 * These functions are NOT in support.s and should be declared elsewhere.
409 */
410void	Debugger	__P((const char *msg));
411u_long	kvtop		__P((void *addr));
412typedef void alias_for_inthand_t __P((u_int cs, u_int ef, u_int esp,
413				      u_int ss));
414void	setidt		__P((int idx, alias_for_inthand_t *func, int typ,
415			     int dpl));
416
417#endif /* !_MACHINE_CPUFUNC_H_ */
418