cpufunc.h revision 10004
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.38 1995/07/25 21:28:47 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" : : : "memory");
67}
68
69static __inline void
70enable_intr(void)
71{
72	__asm __volatile("sti" : : : "memory");
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/*
300 * XXX queue stuff belongs elsewhere.
301 */
302struct quehead {
303	struct quehead *qh_link;
304	struct quehead *qh_rlink;
305};
306
307static __inline void
308insque(void *a, void *b)
309{
310	struct quehead *element = a, *head = b;
311
312	element->qh_link = head->qh_link;
313	element->qh_rlink = head;
314	head->qh_link = element;
315	element->qh_link->qh_rlink = element;
316}
317
318static __inline void
319remque(void *a)
320{
321	struct quehead *element = a;
322
323	element->qh_link->qh_rlink = element->qh_rlink;
324	element->qh_rlink->qh_link = element->qh_link;
325	element->qh_rlink = 0;
326}
327
328#else /* !__GNUC__ */
329
330int	bdb		__P((void));
331void	disable_intr	__P((void));
332void	enable_intr	__P((void));
333u_char	inb		__P((u_int port));
334u_long	inl		__P((u_int port));
335void	insb		__P((u_int port, void *addr, size_t cnt));
336void	insl		__P((u_int port, void *addr, size_t cnt));
337void	insw		__P((u_int port, void *addr, size_t cnt));
338u_short	inw		__P((u_int port));
339u_int	loadandclear	__P((u_int *addr));
340void	outb		__P((u_int port, u_char data));
341void	outl		__P((u_int port, u_long data));
342void	outsb		__P((u_int port, void *addr, size_t cnt));
343void	outsl		__P((u_int port, void *addr, size_t cnt));
344void	outsw		__P((u_int port, void *addr, size_t cnt));
345void	outw		__P((u_int port, u_short data));
346void	pmap_update	__P((void));
347u_long	read_eflags	__P((void));
348u_long	rcr2		__P((void));
349void	write_eflags	__P((u_long ef));
350
351void	insque		__P((void *a, void *b));
352void	remque		__P((void *a));
353
354#endif	/* __GNUC__ */
355
356/*
357 * XXX the following declarations document garbage in support.s.
358 * gcc hasn't needed _divsi* for years.
359 * bcopy[bwx]() was used by pccons but isn't used now.
360 */
361int	__divsi3	__P((int factor1, int factor2));
362u_int	__udivsi3	__P((u_int factor1, u_int factor2));
363void	bcopyb		__P((const void *from, void *to, size_t len));
364void	bcopyw		__P((const void *from, void *to, size_t len));
365void	bcopyx		__P((const void *from, void *to, size_t len,
366			     int stride));
367
368#if 0
369/*
370 * These functions in support.s are declared elsewhere.
371 */
372void	bcopy		__P((const void *from, void *to, size_t len));
373void	blkclr		__P((void *buf, size_t len));
374void	bzero		__P((void *buf, size_t len));
375int	copyin		__P((void *udaddr, void *kaddr, size_t len));
376int	copyinstr	__P((void *udaddr, void *kaddr, size_t len,
377			     size_t *lencopied));
378int	copyout		__P((void *kaddr, void *udaddr, size_t len));
379int	copystr		__P((void *kfaddr, void *kdaddr, size_t len,
380			     size_t *lencopied));
381int	fubyte		__P((void *base));
382int	fuswintr	__P((void *base));
383int	fuibyte		__P((void *base));
384int	fuword		__P((void *base));
385struct	region_descriptor;
386void	lgdt		__P((struct region_descriptor *rdp));
387void	lidt		__P((struct region_descriptor *rdp));
388void	lldt		__P((u_short sel));
389/*
390 * longjmp() and setjmp() are only used by ddb.  They probably shouldn't
391 * shouldn't be supported in the kernel.
392 */
393#include <setjmp.h>
394void	longjmp		__P((jmp_buf jb, int rv));
395void	ovbcopy		__P((const void *from, void *to, size_t len);
396int	setjmp		__P((jmp_buf jb));
397struct soft_segment_descriptor;
398union descriptor;
399int	ssdtosd		__P((struct soft_segment_descriptor *ssdp,
400			     union descriptor *sdp));
401int	subyte		__P((void *base, int byte));
402int	suibyte		__P((void *base, int byte));
403int	suswintr	__P((void *base, int word));
404int	suword		__P((void *base, int word));
405
406/*
407 * These functions in support.s are declared elsewhere, but never used.
408 * A silly amount of effort went into copyoutstr().  It's not worth
409 * maintaining, since the string length is usually known so copyout
410 * works better, or is easy to find so copyout() can be used.
411 */
412int	copyoutstr	__P((void *kaddr, void *udaddr, size_t len,
413			     size_t *lencopied));
414int	fuiword		__P((void *base));
415int	suiword		__P((void *base, int word));
416
417/*
418 * These functions in support.s are also in libkern.a and are declared in
419 * libkern.h.
420 * ffs() is built in to gcc-2 and was buggy in gcc-2.4.5 so we may may the
421 * buggy version if we don't replace it by an inline.
422 */
423int	bcmp		__P((const void *b1, const void *b2, size_t length));
424int	ffs		__P((int mask));
425#endif /* 0 */
426
427/*
428 * These variables and functions in support.s are used.
429 */
430extern u_int atdevbase;	/* offset in virtual memory of ISA io mem */
431
432void	filli		__P((int pat, void *base, size_t cnt));
433void	fillw		__P((int /*u_short*/ pat, void *base, size_t cnt));
434int	fusword		__P((void *base));
435void	load_cr0	__P((u_long cr0));
436void	load_cr3	__P((u_long cr3));
437void	ltr		__P((u_short sel));
438u_int	rcr0		__P((void));
439u_long	rcr3		__P((void));
440int	rtcin		__P((int val));
441
442/*
443 * These functions are NOT in support.s and should be declared elsewhere.
444 */
445void	Debugger	__P((const char *msg));
446u_long	kvtop		__P((void *addr));
447typedef void alias_for_inthand_t __P((u_int cs, u_int ef, u_int esp,
448				      u_int ss));
449void	setidt		__P((int idx, alias_for_inthand_t *func, int typ,
450			     int dpl));
451
452#endif /* !_MACHINE_CPUFUNC_H_ */
453