cpufunc.h revision 6503
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.32 1995/02/14 06:51:31 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");
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 * Use an expression-statement instead of a conditional expression
105 * because gcc-2.6.0 would promote the operands of the conditional
106 * and produce poor code for "if ((inb(var) & const1) == const2)".
107 */
108#define	inb(port)	({						\
109	u_char	_data;							\
110	if (__builtin_constant_p((int) (port)) && (port) < 256ul)	\
111		_data = inbc(port);					\
112	else								\
113		_data = inbv(port);					\
114	_data; })
115
116#define	outb(port, data) \
117	(__builtin_constant_p((int) (port)) && (port) < 256ul \
118	 ? outbc(port, data) : outbv(port, data))
119
120static __inline u_char
121inbc(u_int port)
122{
123	u_char	data;
124
125	__asm __volatile("inb %1,%0" : "=a" (data) : "i" (port));
126	return (data);
127}
128
129static __inline void
130outbc(u_int port, u_char data)
131{
132	__asm __volatile("outb %0,%1" : : "a" (data), "i" (port));
133}
134
135#endif /* __GNUC <= 2 */
136
137static __inline u_char
138inbv(u_int port)
139{
140	u_char	data;
141	/*
142	 * We use %%dx and not %1 here because i/o is done at %dx and not at
143	 * %edx, while gcc generates inferior code (movw instead of movl)
144	 * if we tell it to load (u_short) port.
145	 */
146	__asm __volatile("inb %%dx,%0" : "=a" (data) : "d" (port));
147	return (data);
148}
149
150static __inline u_long
151inl(u_int port)
152{
153	u_long	data;
154
155	__asm __volatile("inl %%dx,%0" : "=a" (data) : "d" (port));
156	return (data);
157}
158
159static __inline void
160insb(u_int port, void *addr, size_t cnt)
161{
162	__asm __volatile("cld; rep; insb"
163			 : : "d" (port), "D" (addr), "c" (cnt)
164			 : "di", "cx", "memory");
165}
166
167static __inline void
168insw(u_int port, void *addr, size_t cnt)
169{
170	__asm __volatile("cld; rep; insw"
171			 : : "d" (port), "D" (addr), "c" (cnt)
172			 : "di", "cx", "memory");
173}
174
175static __inline void
176insl(u_int port, void *addr, size_t cnt)
177{
178	__asm __volatile("cld; rep; insl"
179			 : : "d" (port), "D" (addr), "c" (cnt)
180			 : "di", "cx", "memory");
181}
182
183static __inline u_short
184inw(u_int port)
185{
186	u_short	data;
187
188	__asm __volatile("inw %%dx,%0" : "=a" (data) : "d" (port));
189	return (data);
190}
191
192static __inline void
193outbv(u_int port, u_char data)
194{
195	u_char	al;
196	/*
197	 * Use an unnecessary assignment to help gcc's register allocator.
198	 * This make a large difference for gcc-1.40 and a tiny difference
199	 * for gcc-2.6.0.  For gcc-1.40, al had to be ``asm("ax")'' for
200	 * best results.  gcc-2.6.0 can't handle this.
201	 */
202	al = data;
203	__asm __volatile("outb %0,%%dx" : : "a" (al), "d" (port));
204}
205
206static __inline void
207outl(u_int port, u_long data)
208{
209	/*
210	 * outl() and outw() aren't used much so we haven't looked at
211	 * possible micro-optimizations such as the unnecessary
212	 * assignment for them.
213	 */
214	__asm __volatile("outl %0,%%dx" : : "a" (data), "d" (port));
215}
216
217static __inline void
218outsb(u_int port, void *addr, size_t cnt)
219{
220	__asm __volatile("cld; rep; outsb"
221			 : : "d" (port), "S" (addr), "c" (cnt)
222			 : "si", "cx");
223}
224
225static __inline void
226outsw(u_int port, void *addr, size_t cnt)
227{
228	__asm __volatile("cld; rep; outsw"
229			 : : "d" (port), "S" (addr), "c" (cnt)
230			 : "si", "cx");
231}
232
233static __inline void
234outsl(u_int port, void *addr, size_t cnt)
235{
236	__asm __volatile("cld; rep; outsl"
237			 : : "d" (port), "S" (addr), "c" (cnt)
238			 : "si", "cx");
239}
240
241static __inline void
242outw(u_int port, u_short data)
243{
244	__asm __volatile("outw %0,%%dx" : : "a" (data), "d" (port));
245}
246
247static __inline void
248pmap_update(void)
249{
250	u_long	temp;
251	/*
252	 * This should be implemented as load_cr3(rcr3()) when load_cr3()
253	 * is inlined.
254	 */
255	__asm __volatile("movl %%cr3, %0; movl %0, %%cr3" : "=r" (temp));
256}
257
258static __inline u_long
259rcr2(void)
260{
261	u_long	data;
262
263	__asm __volatile("movl %%cr2,%0" : "=r" (data));
264	return (data);
265}
266
267static __inline u_long
268read_eflags(void)
269{
270	u_long	ef;
271
272	__asm __volatile("pushfl; popl %0" : "=r" (ef));
273	return (ef);
274}
275
276static __inline void
277write_eflags(u_long ef)
278{
279	__asm __volatile("pushl %0; popfl" : : "r" (ef));
280}
281
282/*
283 * XXX queue stuff belongs elsewhere.
284 */
285struct quehead {
286	struct quehead *qh_link;
287	struct quehead *qh_rlink;
288};
289
290static __inline void
291insque(void *a, void *b)
292{
293	struct quehead *element = a, *head = b;
294
295	element->qh_link = head->qh_link;
296	head->qh_link = element;
297	element->qh_rlink = head;
298	element->qh_link->qh_rlink = element;
299}
300
301static __inline void
302remque(void *a)
303{
304	struct quehead *element = a;
305
306	element->qh_link->qh_rlink = element->qh_rlink;
307	element->qh_rlink->qh_link = element->qh_link;
308	element->qh_rlink = 0;
309}
310
311#else /* !__GNUC__ */
312
313int	bdb		__P((void));
314void	disable_intr	__P((void));
315void	enable_intr	__P((void));
316u_char	inb		__P((u_int port));
317u_long	inl		__P((u_int port));
318void	insb		__P((u_int port, void *addr, size_t cnt));
319void	insl		__P((u_int port, void *addr, size_t cnt));
320void	insw		__P((u_int port, void *addr, size_t cnt));
321u_short	inw		__P((u_int port));
322void	outb		__P((u_int port, u_char data));
323void	outl		__P((u_int port, u_long data));
324void	outsb		__P((u_int port, void *addr, size_t cnt));
325void	outsl		__P((u_int port, void *addr, size_t cnt));
326void	outsw		__P((u_int port, void *addr, size_t cnt));
327void	outw		__P((u_int port, u_short data));
328void	pmap_update	__P((void));
329u_long	read_eflags	__P((void));
330u_long	rcr2		__P((void));
331void	write_eflags	__P((u_long ef));
332
333void	insque		__P((void *a, void *b));
334void	remque		__P((void *a));
335
336#endif	/* __GNUC__ */
337
338/*
339 * XXX the following declarations document garbage in support.s.
340 * gcc hasn't needed _divsi* for years.
341 * bcopy[bwx]() was used by pccons but isn't used now.
342 */
343int	__divsi3	__P((int factor1, int factor2));
344u_int	__udivsi3	__P((u_int factor1, u_int factor2));
345void	bcopyb		__P((const void *from, void *to, size_t len));
346void	bcopyw		__P((const void *from, void *to, size_t len));
347void	bcopyx		__P((const void *from, void *to, size_t len,
348			     int stride));
349
350#if 0
351/*
352 * These functions in support.s are declared elsewhere.
353 */
354void	bcopy		__P((const void *from, void *to, size_t len));
355void	blkclr		__P((void *buf, size_t len));
356void	bzero		__P((void *buf, size_t len));
357int	copyin		__P((void *udaddr, void *kaddr, size_t len));
358int	copyinstr	__P((void *udaddr, void *kaddr, size_t len,
359			     size_t *lencopied));
360int	copyout		__P((void *kaddr, void *udaddr, size_t len));
361int	copystr		__P((void *kfaddr, void *kdaddr, size_t len,
362			     size_t *lencopied));
363int	fubyte		__P((void *base));
364int	fuswintr	__P((void *base));
365int	fuibyte		__P((void *base));
366int	fuword		__P((void *base));
367struct	region_descriptor;
368void	lgdt		__P((struct region_descriptor *rdp));
369void	lidt		__P((struct region_descriptor *rdp));
370void	lldt		__P((u_short sel));
371/*
372 * longjmp() and setjmp() are only used by ddb.  They probably shouldn't
373 * shouldn't be supported in the kernel.
374 */
375#include <setjmp.h>
376void	longjmp		__P((jmp_buf jb, int rv));
377void	ovbcopy		__P((const void *from, void *to, size_t len);
378int	setjmp		__P((jmp_buf jb));
379struct soft_segment_descriptor;
380union descriptor;
381int	ssdtosd		__P((struct soft_segment_descriptor *ssdp,
382			     union descriptor *sdp));
383int	subyte		__P((void *base, int byte));
384int	suibyte		__P((void *base, int byte));
385int	suswintr	__P((void *base, int word));
386int	suword		__P((void *base, int word));
387
388/*
389 * These functions in support.s are declared elsewhere, but never used.
390 * A silly amount of effort went into copyoutstr().  It's not worth
391 * maintaining, since the string length is usually known so copyout
392 * works better, or is easy to find so copyout() can be used.
393 */
394int	copyoutstr	__P((void *kaddr, void *udaddr, size_t len,
395			     size_t *lencopied));
396int	fuiword		__P((void *base));
397int	suiword		__P((void *base, int word));
398
399/*
400 * These functions in support.s are also in libkern.a and are declared in
401 * libkern.h.
402 * ffs() is built in to gcc-2 and was buggy in gcc-2.4.5 so we may may the
403 * buggy version if we don't replace it by an inline.
404 */
405int	bcmp		__P((const void *b1, const void *b2, size_t length));
406int	ffs		__P((int mask));
407#endif /* 0 */
408
409/*
410 * These variables and functions in support.s are used.
411 */
412extern u_int atdevbase;	/* offset in virtual memory of ISA io mem */
413
414void	filli		__P((int pat, void *base, size_t cnt));
415void	fillw		__P((int /*u_short*/ pat, void *base, size_t cnt));
416int	fusword		__P((void *base));
417void	load_cr0	__P((u_long cr0));
418void	load_cr3	__P((u_long cr3));
419void	ltr		__P((u_short sel));
420u_int	rcr0		__P((void));
421u_long	rcr3		__P((void));
422int	rtcin		__P((int val));
423
424/*
425 * These functions are NOT in support.s and should be declared elsewhere.
426 */
427void	Debugger	__P((const char *msg));
428u_long	kvtop		__P((void *addr));
429typedef void alias_for_inthand_t __P((u_int cs, u_int ef, u_int esp,
430				      u_int ss));
431void	setidt		__P((int idx, alias_for_inthand_t *func, int typ,
432			     int dpl));
433
434#endif /* !_MACHINE_CPUFUNC_H_ */
435