xref: /freebsd/sys/i386/include/cpufunc.h (revision 17ee9d00bc1ae1e598c38f25826f861e4bc6c3ce)
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
51 extern int	bdb_exists;
52 
53 static __inline int
54 bdb(void)
55 {
56 	if (!bdb_exists)
57 		return (0);
58 	__asm __volatile("int $3");
59 	return (1);
60 }
61 #endif /* BDE_DEBUGGER */
62 
63 static __inline void
64 disable_intr(void)
65 {
66 	__asm __volatile("cli");
67 }
68 
69 static __inline void
70 enable_intr(void)
71 {
72 	__asm __volatile("sti");
73 }
74 
75 #define	HAVE_INLINE_FFS
76 
77 static __inline int
78 ffs(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 
120 static __inline u_char
121 inbc(u_int port)
122 {
123 	u_char	data;
124 
125 	__asm __volatile("inb %1,%0" : "=a" (data) : "i" (port));
126 	return (data);
127 }
128 
129 static __inline void
130 outbc(u_int port, u_char data)
131 {
132 	__asm __volatile("outb %0,%1" : : "a" (data), "i" (port));
133 }
134 
135 #endif /* __GNUC <= 2 */
136 
137 static __inline u_char
138 inbv(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 
150 static __inline u_long
151 inl(u_int port)
152 {
153 	u_long	data;
154 
155 	__asm __volatile("inl %%dx,%0" : "=a" (data) : "d" (port));
156 	return (data);
157 }
158 
159 static __inline void
160 insb(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 
167 static __inline void
168 insw(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 
175 static __inline void
176 insl(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 
183 static __inline u_short
184 inw(u_int port)
185 {
186 	u_short	data;
187 
188 	__asm __volatile("inw %%dx,%0" : "=a" (data) : "d" (port));
189 	return (data);
190 }
191 
192 static __inline void
193 outbv(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 
206 static __inline void
207 outl(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 
217 static __inline void
218 outsb(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 
225 static __inline void
226 outsw(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 
233 static __inline void
234 outsl(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 
241 static __inline void
242 outw(u_int port, u_short data)
243 {
244 	__asm __volatile("outw %0,%%dx" : : "a" (data), "d" (port));
245 }
246 
247 static __inline void
248 pmap_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 
258 static __inline u_long
259 rcr2(void)
260 {
261 	u_long	data;
262 
263 	__asm __volatile("movl %%cr2,%0" : "=r" (data));
264 	return (data);
265 }
266 
267 static __inline u_long
268 read_eflags(void)
269 {
270 	u_long	ef;
271 
272 	__asm __volatile("pushfl; popl %0" : "=r" (ef));
273 	return (ef);
274 }
275 
276 static __inline void
277 write_eflags(u_long ef)
278 {
279 	__asm __volatile("pushl %0; popfl" : : "r" (ef));
280 }
281 
282 /*
283  * XXX queue stuff belongs elsewhere.
284  */
285 struct quehead {
286 	struct quehead *qh_link;
287 	struct quehead *qh_rlink;
288 };
289 
290 static __inline void
291 insque(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 
301 static __inline void
302 remque(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 
313 int	bdb		__P((void));
314 void	disable_intr	__P((void));
315 void	enable_intr	__P((void));
316 u_char	inb		__P((u_int port));
317 u_long	inl		__P((u_int port));
318 void	insb		__P((u_int port, void *addr, size_t cnt));
319 void	insl		__P((u_int port, void *addr, size_t cnt));
320 void	insw		__P((u_int port, void *addr, size_t cnt));
321 u_short	inw		__P((u_int port));
322 void	outb		__P((u_int port, u_char data));
323 void	outl		__P((u_int port, u_long data));
324 void	outsb		__P((u_int port, void *addr, size_t cnt));
325 void	outsl		__P((u_int port, void *addr, size_t cnt));
326 void	outsw		__P((u_int port, void *addr, size_t cnt));
327 void	outw		__P((u_int port, u_short data));
328 void	pmap_update	__P((void));
329 u_long	read_eflags	__P((void));
330 u_long	rcr2		__P((void));
331 void	write_eflags	__P((u_long ef));
332 
333 void	insque		__P((void *a, void *b));
334 void	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  */
343 int	__divsi3	__P((int factor1, int factor2));
344 u_int	__udivsi3	__P((u_int factor1, u_int factor2));
345 void	bcopyb		__P((const void *from, void *to, size_t len));
346 void	bcopyw		__P((const void *from, void *to, size_t len));
347 void	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  */
354 void	bcopy		__P((const void *from, void *to, size_t len));
355 void	blkclr		__P((void *buf, size_t len));
356 void	bzero		__P((void *buf, size_t len));
357 int	copyin		__P((void *udaddr, void *kaddr, size_t len));
358 int	copyinstr	__P((void *udaddr, void *kaddr, size_t len,
359 			     size_t *lencopied));
360 int	copyout		__P((void *kaddr, void *udaddr, size_t len));
361 int	copystr		__P((void *kfaddr, void *kdaddr, size_t len,
362 			     size_t *lencopied));
363 int	fubyte		__P((void *base));
364 int	fuswintr	__P((void *base));
365 int	fuibyte		__P((void *base));
366 int	fuword		__P((void *base));
367 struct	region_descriptor;
368 void	lgdt		__P((struct region_descriptor *rdp));
369 void	lidt		__P((struct region_descriptor *rdp));
370 void	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>
376 void	longjmp		__P((jmp_buf jb, int rv));
377 void	ovbcopy		__P((const void *from, void *to, size_t len);
378 int	setjmp		__P((jmp_buf jb));
379 struct soft_segment_descriptor;
380 union descriptor;
381 int	ssdtosd		__P((struct soft_segment_descriptor *ssdp,
382 			     union descriptor *sdp));
383 int	subyte		__P((void *base, int byte));
384 int	suibyte		__P((void *base, int byte));
385 int	suswintr	__P((void *base, int word));
386 int	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  */
394 int	copyoutstr	__P((void *kaddr, void *udaddr, size_t len,
395 			     size_t *lencopied));
396 int	fuiword		__P((void *base));
397 int	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  */
405 int	bcmp		__P((const void *b1, const void *b2, size_t length));
406 int	ffs		__P((int mask));
407 #endif /* 0 */
408 
409 /*
410  * These variables and functions in support.s are used.
411  */
412 extern u_int atdevbase;	/* offset in virtual memory of ISA io mem */
413 
414 void	filli		__P((int pat, void *base, size_t cnt));
415 void	fillw		__P((int /*u_short*/ pat, void *base, size_t cnt));
416 int	fusword		__P((void *base));
417 void	load_cr0	__P((u_long cr0));
418 void	load_cr3	__P((u_long cr3));
419 void	ltr		__P((u_short sel));
420 u_int	rcr0		__P((void));
421 u_long	rcr3		__P((void));
422 int	rtcin		__P((int val));
423 
424 /*
425  * These functions are NOT in support.s and should be declared elsewhere.
426  */
427 void	Debugger	__P((const char *msg));
428 u_long	kvtop		__P((void *addr));
429 typedef void alias_for_inthand_t __P((u_int cs, u_int ef, u_int esp,
430 				      u_int ss));
431 void	setidt		__P((int idx, alias_for_inthand_t *func, int typ,
432 			     int dpl));
433 
434 #endif /* !_MACHINE_CPUFUNC_H_ */
435