cpufunc.h revision 69006
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 * $FreeBSD: head/sys/i386/include/cpufunc.h 69006 2000-11-21 20:16:49Z markm $
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#define readb(va)	(*(volatile u_int8_t *) (va))
44#define readw(va)	(*(volatile u_int16_t *) (va))
45#define readl(va)	(*(volatile u_int32_t *) (va))
46
47#define writeb(va, d)	(*(volatile u_int8_t *) (va) = (d))
48#define writew(va, d)	(*(volatile u_int16_t *) (va) = (d))
49#define writel(va, d)	(*(volatile u_int32_t *) (va) = (d))
50
51#ifdef	__GNUC__
52
53#ifdef SWTCH_OPTIM_STATS
54extern	int	tlb_flush_count;	/* XXX */
55#endif
56
57static __inline void
58breakpoint(void)
59{
60	__asm __volatile("int $3");
61}
62
63static __inline u_int
64bsfl(u_int mask)
65{
66	u_int	result;
67
68	__asm __volatile("bsfl %0,%0" : "=r" (result) : "0" (mask));
69	return (result);
70}
71
72static __inline u_int
73bsrl(u_int mask)
74{
75	u_int	result;
76
77	__asm __volatile("bsrl %0,%0" : "=r" (result) : "0" (mask));
78	return (result);
79}
80
81static __inline void
82disable_intr(void)
83{
84	__asm __volatile("cli" : : : "memory");
85}
86
87static __inline void
88enable_intr(void)
89{
90	__asm __volatile("sti");
91}
92
93static __inline u_int
94save_intr(void)
95{
96	u_int	ef;
97
98	__asm __volatile("pushfl; popl %0" : "=r" (ef));
99	return (ef);
100}
101
102static __inline void
103restore_intr(u_int ef)
104{
105	__asm __volatile("pushl %0; popfl" : : "r" (ef) : "memory" );
106}
107
108#define	HAVE_INLINE_FFS
109
110static __inline int
111ffs(int mask)
112{
113	/*
114	 * Note that gcc-2's builtin ffs would be used if we didn't declare
115	 * this inline or turn off the builtin.  The builtin is faster but
116	 * broken in gcc-2.4.5 and slower but working in gcc-2.5 and later
117	 * versions.
118	 */
119	 return (mask == 0 ? mask : bsfl((u_int)mask) + 1);
120}
121
122#define	HAVE_INLINE_FLS
123
124static __inline int
125fls(int mask)
126{
127	return (mask == 0 ? mask : bsrl((u_int)mask) + 1);
128}
129
130#if __GNUC__ < 2
131
132#define	inb(port)		inbv(port)
133#define	outb(port, data)	outbv(port, data)
134
135#else /* __GNUC >= 2 */
136
137/*
138 * The following complications are to get around gcc not having a
139 * constraint letter for the range 0..255.  We still put "d" in the
140 * constraint because "i" isn't a valid constraint when the port
141 * isn't constant.  This only matters for -O0 because otherwise
142 * the non-working version gets optimized away.
143 *
144 * Use an expression-statement instead of a conditional expression
145 * because gcc-2.6.0 would promote the operands of the conditional
146 * and produce poor code for "if ((inb(var) & const1) == const2)".
147 *
148 * The unnecessary test `(port) < 0x10000' is to generate a warning if
149 * the `port' has type u_short or smaller.  Such types are pessimal.
150 * This actually only works for signed types.  The range check is
151 * careful to avoid generating warnings.
152 */
153#define	inb(port) __extension__ ({					\
154	u_char	_data;							\
155	if (__builtin_constant_p(port) && ((port) & 0xffff) < 0x100	\
156	    && (port) < 0x10000)					\
157		_data = inbc(port);					\
158	else								\
159		_data = inbv(port);					\
160	_data; })
161
162#define	outb(port, data) (						\
163	__builtin_constant_p(port) && ((port) & 0xffff) < 0x100		\
164	&& (port) < 0x10000						\
165	? outbc(port, data) : outbv(port, data))
166
167static __inline u_char
168inbc(u_int port)
169{
170	u_char	data;
171
172	__asm __volatile("inb %1,%0" : "=a" (data) : "id" ((u_short)(port)));
173	return (data);
174}
175
176static __inline void
177outbc(u_int port, u_char data)
178{
179	__asm __volatile("outb %0,%1" : : "a" (data), "id" ((u_short)(port)));
180}
181
182#endif /* __GNUC <= 2 */
183
184static __inline u_char
185inbv(u_int port)
186{
187	u_char	data;
188	/*
189	 * We use %%dx and not %1 here because i/o is done at %dx and not at
190	 * %edx, while gcc generates inferior code (movw instead of movl)
191	 * if we tell it to load (u_short) port.
192	 */
193	__asm __volatile("inb %%dx,%0" : "=a" (data) : "d" (port));
194	return (data);
195}
196
197static __inline u_int
198inl(u_int port)
199{
200	u_int	data;
201
202	__asm __volatile("inl %%dx,%0" : "=a" (data) : "d" (port));
203	return (data);
204}
205
206static __inline void
207insb(u_int port, void *addr, size_t cnt)
208{
209	__asm __volatile("cld; rep; insb"
210			 : "=D" (addr), "=c" (cnt)
211			 :  "0" (addr),  "1" (cnt), "d" (port)
212			 : "memory");
213}
214
215static __inline void
216insw(u_int port, void *addr, size_t cnt)
217{
218	__asm __volatile("cld; rep; insw"
219			 : "=D" (addr), "=c" (cnt)
220			 :  "0" (addr),  "1" (cnt), "d" (port)
221			 : "memory");
222}
223
224static __inline void
225insl(u_int port, void *addr, size_t cnt)
226{
227	__asm __volatile("cld; rep; insl"
228			 : "=D" (addr), "=c" (cnt)
229			 :  "0" (addr),  "1" (cnt), "d" (port)
230			 : "memory");
231}
232
233static __inline void
234invd(void)
235{
236	__asm __volatile("invd");
237}
238
239#if defined(SMP) && defined(_KERNEL)
240
241/*
242 * When using APIC IPI's, invlpg() is not simply the invlpg instruction
243 * (this is a bug) and the inlining cost is prohibitive since the call
244 * executes into the IPI transmission system.
245 */
246void	invlpg		__P((u_int addr));
247void	invltlb		__P((void));
248
249static __inline void
250cpu_invlpg(void *addr)
251{
252	__asm __volatile("invlpg %0" : : "m" (*(char *)addr) : "memory");
253}
254
255static __inline void
256cpu_invltlb(void)
257{
258	u_int	temp;
259	/*
260	 * This should be implemented as load_cr3(rcr3()) when load_cr3()
261	 * is inlined.
262	 */
263	__asm __volatile("movl %%cr3, %0; movl %0, %%cr3" : "=r" (temp)
264			 : : "memory");
265#if defined(SWTCH_OPTIM_STATS)
266	++tlb_flush_count;
267#endif
268}
269
270#else /* !(SMP && _KERNEL) */
271
272static __inline void
273invlpg(u_int addr)
274{
275	__asm __volatile("invlpg %0" : : "m" (*(char *)addr) : "memory");
276}
277
278static __inline void
279invltlb(void)
280{
281	u_int	temp;
282	/*
283	 * This should be implemented as load_cr3(rcr3()) when load_cr3()
284	 * is inlined.
285	 */
286	__asm __volatile("movl %%cr3, %0; movl %0, %%cr3" : "=r" (temp)
287			 : : "memory");
288#ifdef SWTCH_OPTIM_STATS
289	++tlb_flush_count;
290#endif
291}
292
293#endif /* SMP && _KERNEL */
294
295static __inline u_short
296inw(u_int port)
297{
298	u_short	data;
299
300	__asm __volatile("inw %%dx,%0" : "=a" (data) : "d" (port));
301	return (data);
302}
303
304static __inline void
305outbv(u_int port, u_char data)
306{
307	u_char	al;
308	/*
309	 * Use an unnecessary assignment to help gcc's register allocator.
310	 * This make a large difference for gcc-1.40 and a tiny difference
311	 * for gcc-2.6.0.  For gcc-1.40, al had to be ``asm("ax")'' for
312	 * best results.  gcc-2.6.0 can't handle this.
313	 */
314	al = data;
315	__asm __volatile("outb %0,%%dx" : : "a" (al), "d" (port));
316}
317
318static __inline void
319outl(u_int port, u_int data)
320{
321	/*
322	 * outl() and outw() aren't used much so we haven't looked at
323	 * possible micro-optimizations such as the unnecessary
324	 * assignment for them.
325	 */
326	__asm __volatile("outl %0,%%dx" : : "a" (data), "d" (port));
327}
328
329static __inline void
330outsb(u_int port, const void *addr, size_t cnt)
331{
332	__asm __volatile("cld; rep; outsb"
333			 : "=S" (addr), "=c" (cnt)
334			 :  "0" (addr),  "1" (cnt), "d" (port));
335}
336
337static __inline void
338outsw(u_int port, const void *addr, size_t cnt)
339{
340	__asm __volatile("cld; rep; outsw"
341			 : "=S" (addr), "=c" (cnt)
342			 :  "0" (addr),  "1" (cnt), "d" (port));
343}
344
345static __inline void
346outsl(u_int port, const void *addr, size_t cnt)
347{
348	__asm __volatile("cld; rep; outsl"
349			 : "=S" (addr), "=c" (cnt)
350			 :  "0" (addr),  "1" (cnt), "d" (port));
351}
352
353static __inline void
354outw(u_int port, u_short data)
355{
356	__asm __volatile("outw %0,%%dx" : : "a" (data), "d" (port));
357}
358
359static __inline u_int
360rcr2(void)
361{
362	u_int	data;
363
364	__asm __volatile("movl %%cr2,%0" : "=r" (data));
365	return (data);
366}
367
368static __inline u_int
369read_eflags(void)
370{
371	u_int	ef;
372
373	__asm __volatile("pushfl; popl %0" : "=r" (ef));
374	return (ef);
375}
376
377static __inline u_int64_t
378rdmsr(u_int msr)
379{
380	u_int64_t rv;
381
382	__asm __volatile("rdmsr" : "=A" (rv) : "c" (msr));
383	return (rv);
384}
385
386static __inline u_int64_t
387rdpmc(u_int pmc)
388{
389	u_int64_t rv;
390
391	__asm __volatile("rdpmc" : "=A" (rv) : "c" (pmc));
392	return (rv);
393}
394
395static __inline u_int64_t
396rdtsc(void)
397{
398	u_int64_t rv;
399
400	__asm __volatile("rdtsc" : "=A" (rv));
401	return (rv);
402}
403
404static __inline void
405wbinvd(void)
406{
407	__asm __volatile("wbinvd");
408}
409
410static __inline void
411write_eflags(u_int ef)
412{
413	__asm __volatile("pushl %0; popfl" : : "r" (ef));
414}
415
416static __inline void
417wrmsr(u_int msr, u_int64_t newval)
418{
419	__asm __volatile("wrmsr" : : "A" (newval), "c" (msr));
420}
421
422static __inline u_int
423rfs(void)
424{
425	u_int sel;
426	__asm __volatile("movl %%fs,%0" : "=rm" (sel));
427	return (sel);
428}
429
430static __inline u_int
431rgs(void)
432{
433	u_int sel;
434	__asm __volatile("movl %%gs,%0" : "=rm" (sel));
435	return (sel);
436}
437
438static __inline void
439load_fs(u_int sel)
440{
441	__asm __volatile("movl %0,%%fs" : : "rm" (sel));
442}
443
444static __inline void
445load_gs(u_int sel)
446{
447	__asm __volatile("movl %0,%%gs" : : "rm" (sel));
448}
449
450static __inline u_int
451rdr0(void)
452{
453	u_int	data;
454	__asm __volatile("movl %%dr0,%0" : "=r" (data));
455	return (data);
456}
457
458static __inline u_int
459rdr1(void)
460{
461	u_int	data;
462	__asm __volatile("movl %%dr1,%0" : "=r" (data));
463	return (data);
464}
465
466static __inline u_int
467rdr2(void)
468{
469	u_int	data;
470	__asm __volatile("movl %%dr2,%0" : "=r" (data));
471	return (data);
472}
473
474static __inline u_int
475rdr3(void)
476{
477	u_int	data;
478	__asm __volatile("movl %%dr3,%0" : "=r" (data));
479	return (data);
480}
481
482static __inline u_int
483rdr6(void)
484{
485	u_int	data;
486	__asm __volatile("movl %%dr6,%0" : "=r" (data));
487	return (data);
488}
489
490static __inline u_int
491rdr7(void)
492{
493	u_int	data;
494	__asm __volatile("movl %%dr7,%0" : "=r" (data));
495	return (data);
496}
497
498#else /* !__GNUC__ */
499
500int	breakpoint	__P((void));
501u_int	bsfl		__P((u_int mask));
502u_int	bsrl		__P((u_int mask));
503void	disable_intr	__P((void));
504void	enable_intr	__P((void));
505u_char	inb		__P((u_int port));
506u_int	inl		__P((u_int port));
507void	insb		__P((u_int port, void *addr, size_t cnt));
508void	insl		__P((u_int port, void *addr, size_t cnt));
509void	insw		__P((u_int port, void *addr, size_t cnt));
510void	invd		__P((void));
511void	invlpg		__P((u_int addr));
512void	invltlb		__P((void));
513u_short	inw		__P((u_int port));
514void	outb		__P((u_int port, u_char data));
515void	outl		__P((u_int port, u_int data));
516void	outsb		__P((u_int port, void *addr, size_t cnt));
517void	outsl		__P((u_int port, void *addr, size_t cnt));
518void	outsw		__P((u_int port, void *addr, size_t cnt));
519void	outw		__P((u_int port, u_short data));
520u_int	rcr2		__P((void));
521u_int64_t rdmsr		__P((u_int msr));
522u_int64_t rdpmc		__P((u_int pmc));
523u_int64_t rdtsc		__P((void));
524u_int	read_eflags	__P((void));
525void	wbinvd		__P((void));
526void	write_eflags	__P((u_int ef));
527void	wrmsr		__P((u_int msr, u_int64_t newval));
528u_int	rfs		__P((void));
529u_int	rgs		__P((void));
530void	load_fs		__P((u_int sel));
531void	load_gs		__P((u_int sel));
532
533#endif	/* __GNUC__ */
534
535void	load_cr0	__P((u_int cr0));
536void	load_cr3	__P((u_int cr3));
537void	load_cr4	__P((u_int cr4));
538void	ltr		__P((u_short sel));
539u_int	rcr0		__P((void));
540u_int	rcr3		__P((void));
541u_int	rcr4		__P((void));
542void    load_dr6        __P((u_int dr6));
543void    reset_dbregs    __P((void));
544
545#endif /* !_MACHINE_CPUFUNC_H_ */
546