cpufunc.h revision 8521
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.35 1995/05/11 07:24:35 bde 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 unsigned
193loadandclear(u_int *addr)
194{
195	u_int	result;
196
197	__asm __volatile("xorl %0,%0; xchgl %1,%0"
198			 : "=&r" (result) : "m" (*addr));
199	return (result);
200}
201
202static __inline void
203outbv(u_int port, u_char data)
204{
205	u_char	al;
206	/*
207	 * Use an unnecessary assignment to help gcc's register allocator.
208	 * This make a large difference for gcc-1.40 and a tiny difference
209	 * for gcc-2.6.0.  For gcc-1.40, al had to be ``asm("ax")'' for
210	 * best results.  gcc-2.6.0 can't handle this.
211	 */
212	al = data;
213	__asm __volatile("outb %0,%%dx" : : "a" (al), "d" (port));
214}
215
216static __inline void
217outl(u_int port, u_long data)
218{
219	/*
220	 * outl() and outw() aren't used much so we haven't looked at
221	 * possible micro-optimizations such as the unnecessary
222	 * assignment for them.
223	 */
224	__asm __volatile("outl %0,%%dx" : : "a" (data), "d" (port));
225}
226
227static __inline void
228outsb(u_int port, void *addr, size_t cnt)
229{
230	__asm __volatile("cld; rep; outsb"
231			 : : "d" (port), "S" (addr), "c" (cnt)
232			 : "si", "cx");
233}
234
235static __inline void
236outsw(u_int port, void *addr, size_t cnt)
237{
238	__asm __volatile("cld; rep; outsw"
239			 : : "d" (port), "S" (addr), "c" (cnt)
240			 : "si", "cx");
241}
242
243static __inline void
244outsl(u_int port, void *addr, size_t cnt)
245{
246	__asm __volatile("cld; rep; outsl"
247			 : : "d" (port), "S" (addr), "c" (cnt)
248			 : "si", "cx");
249}
250
251static __inline void
252outw(u_int port, u_short data)
253{
254	__asm __volatile("outw %0,%%dx" : : "a" (data), "d" (port));
255}
256
257static __inline void
258pmap_update(void)
259{
260	u_long	temp;
261	/*
262	 * This should be implemented as load_cr3(rcr3()) when load_cr3()
263	 * is inlined.
264	 */
265	__asm __volatile("movl %%cr3, %0; movl %0, %%cr3" : "=r" (temp));
266}
267
268static __inline u_long
269rcr2(void)
270{
271	u_long	data;
272
273	__asm __volatile("movl %%cr2,%0" : "=r" (data));
274	return (data);
275}
276
277static __inline u_long
278read_eflags(void)
279{
280	u_long	ef;
281
282	__asm __volatile("pushfl; popl %0" : "=r" (ef));
283	return (ef);
284}
285
286static __inline void
287write_eflags(u_long ef)
288{
289	__asm __volatile("pushl %0; popfl" : : "r" (ef));
290}
291
292/*
293 * XXX queue stuff belongs elsewhere.
294 */
295struct quehead {
296	struct quehead *qh_link;
297	struct quehead *qh_rlink;
298};
299
300static __inline void
301insque(void *a, void *b)
302{
303	struct quehead *element = a, *head = b;
304
305	element->qh_link = head->qh_link;
306	element->qh_rlink = head;
307	head->qh_link = element;
308	element->qh_link->qh_rlink = element;
309}
310
311static __inline void
312remque(void *a)
313{
314	struct quehead *element = a;
315
316	element->qh_link->qh_rlink = element->qh_rlink;
317	element->qh_rlink->qh_link = element->qh_link;
318	element->qh_rlink = 0;
319}
320
321#else /* !__GNUC__ */
322
323int	bdb		__P((void));
324void	disable_intr	__P((void));
325void	enable_intr	__P((void));
326u_char	inb		__P((u_int port));
327u_long	inl		__P((u_int port));
328void	insb		__P((u_int port, void *addr, size_t cnt));
329void	insl		__P((u_int port, void *addr, size_t cnt));
330void	insw		__P((u_int port, void *addr, size_t cnt));
331u_short	inw		__P((u_int port));
332u_int	loadandclear	__P((u_int *addr));
333void	outb		__P((u_int port, u_char data));
334void	outl		__P((u_int port, u_long data));
335void	outsb		__P((u_int port, void *addr, size_t cnt));
336void	outsl		__P((u_int port, void *addr, size_t cnt));
337void	outsw		__P((u_int port, void *addr, size_t cnt));
338void	outw		__P((u_int port, u_short data));
339void	pmap_update	__P((void));
340u_long	read_eflags	__P((void));
341u_long	rcr2		__P((void));
342void	write_eflags	__P((u_long ef));
343
344void	insque		__P((void *a, void *b));
345void	remque		__P((void *a));
346
347#endif	/* __GNUC__ */
348
349/*
350 * XXX the following declarations document garbage in support.s.
351 * gcc hasn't needed _divsi* for years.
352 * bcopy[bwx]() was used by pccons but isn't used now.
353 */
354int	__divsi3	__P((int factor1, int factor2));
355u_int	__udivsi3	__P((u_int factor1, u_int factor2));
356void	bcopyb		__P((const void *from, void *to, size_t len));
357void	bcopyw		__P((const void *from, void *to, size_t len));
358void	bcopyx		__P((const void *from, void *to, size_t len,
359			     int stride));
360
361#if 0
362/*
363 * These functions in support.s are declared elsewhere.
364 */
365void	bcopy		__P((const void *from, void *to, size_t len));
366void	blkclr		__P((void *buf, size_t len));
367void	bzero		__P((void *buf, size_t len));
368int	copyin		__P((void *udaddr, void *kaddr, size_t len));
369int	copyinstr	__P((void *udaddr, void *kaddr, size_t len,
370			     size_t *lencopied));
371int	copyout		__P((void *kaddr, void *udaddr, size_t len));
372int	copystr		__P((void *kfaddr, void *kdaddr, size_t len,
373			     size_t *lencopied));
374int	fubyte		__P((void *base));
375int	fuswintr	__P((void *base));
376int	fuibyte		__P((void *base));
377int	fuword		__P((void *base));
378struct	region_descriptor;
379void	lgdt		__P((struct region_descriptor *rdp));
380void	lidt		__P((struct region_descriptor *rdp));
381void	lldt		__P((u_short sel));
382/*
383 * longjmp() and setjmp() are only used by ddb.  They probably shouldn't
384 * shouldn't be supported in the kernel.
385 */
386#include <setjmp.h>
387void	longjmp		__P((jmp_buf jb, int rv));
388void	ovbcopy		__P((const void *from, void *to, size_t len);
389int	setjmp		__P((jmp_buf jb));
390struct soft_segment_descriptor;
391union descriptor;
392int	ssdtosd		__P((struct soft_segment_descriptor *ssdp,
393			     union descriptor *sdp));
394int	subyte		__P((void *base, int byte));
395int	suibyte		__P((void *base, int byte));
396int	suswintr	__P((void *base, int word));
397int	suword		__P((void *base, int word));
398
399/*
400 * These functions in support.s are declared elsewhere, but never used.
401 * A silly amount of effort went into copyoutstr().  It's not worth
402 * maintaining, since the string length is usually known so copyout
403 * works better, or is easy to find so copyout() can be used.
404 */
405int	copyoutstr	__P((void *kaddr, void *udaddr, size_t len,
406			     size_t *lencopied));
407int	fuiword		__P((void *base));
408int	suiword		__P((void *base, int word));
409
410/*
411 * These functions in support.s are also in libkern.a and are declared in
412 * libkern.h.
413 * ffs() is built in to gcc-2 and was buggy in gcc-2.4.5 so we may may the
414 * buggy version if we don't replace it by an inline.
415 */
416int	bcmp		__P((const void *b1, const void *b2, size_t length));
417int	ffs		__P((int mask));
418#endif /* 0 */
419
420/*
421 * These variables and functions in support.s are used.
422 */
423extern u_int atdevbase;	/* offset in virtual memory of ISA io mem */
424
425void	filli		__P((int pat, void *base, size_t cnt));
426void	fillw		__P((int /*u_short*/ pat, void *base, size_t cnt));
427int	fusword		__P((void *base));
428void	load_cr0	__P((u_long cr0));
429void	load_cr3	__P((u_long cr3));
430void	ltr		__P((u_short sel));
431u_int	rcr0		__P((void));
432u_long	rcr3		__P((void));
433int	rtcin		__P((int val));
434
435/*
436 * These functions are NOT in support.s and should be declared elsewhere.
437 */
438void	Debugger	__P((const char *msg));
439u_long	kvtop		__P((void *addr));
440typedef void alias_for_inthand_t __P((u_int cs, u_int ef, u_int esp,
441				      u_int ss));
442void	setidt		__P((int idx, alias_for_inthand_t *func, int typ,
443			     int dpl));
444
445#endif /* !_MACHINE_CPUFUNC_H_ */
446