cpufunc.h revision 126656
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 126656 2004-03-05 15:30:40Z bde $
34 */
35
36/*
37 * Functions to provide access to special i386 instructions.
38 * This in included in sys/systm.h, and that file should be
39 * used in preference to this.
40 */
41
42#ifndef _MACHINE_CPUFUNC_H_
43#define	_MACHINE_CPUFUNC_H_
44
45struct region_descriptor;
46
47#define readb(va)	(*(volatile u_int8_t *) (va))
48#define readw(va)	(*(volatile u_int16_t *) (va))
49#define readl(va)	(*(volatile u_int32_t *) (va))
50
51#define writeb(va, d)	(*(volatile u_int8_t *) (va) = (d))
52#define writew(va, d)	(*(volatile u_int16_t *) (va) = (d))
53#define writel(va, d)	(*(volatile u_int32_t *) (va) = (d))
54
55#ifdef	__GNUC__
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 %1,%0" : "=r" (result) : "rm" (mask));
69	return (result);
70}
71
72static __inline u_int
73bsrl(u_int mask)
74{
75	u_int	result;
76
77	__asm __volatile("bsrl %1,%0" : "=r" (result) : "rm" (mask));
78	return (result);
79}
80
81static __inline void
82disable_intr(void)
83{
84	__asm __volatile("cli" : : : "memory");
85}
86
87static __inline void
88do_cpuid(u_int ax, u_int *p)
89{
90	__asm __volatile("cpuid"
91			 : "=a" (p[0]), "=b" (p[1]), "=c" (p[2]), "=d" (p[3])
92			 :  "0" (ax));
93}
94
95static __inline void
96enable_intr(void)
97{
98	__asm __volatile("sti");
99}
100
101#define	HAVE_INLINE_FFS
102
103static __inline int
104ffs(int mask)
105{
106	/*
107	 * Note that gcc-2's builtin ffs would be used if we didn't declare
108	 * this inline or turn off the builtin.  The builtin is faster but
109	 * broken in gcc-2.4.5 and slower but working in gcc-2.5 and later
110	 * versions.
111	 */
112	 return (mask == 0 ? mask : (int)bsfl((u_int)mask) + 1);
113}
114
115#define	HAVE_INLINE_FLS
116
117static __inline int
118fls(int mask)
119{
120	return (mask == 0 ? mask : (int)bsrl((u_int)mask) + 1);
121}
122
123static __inline void
124halt(void)
125{
126	__asm __volatile("hlt");
127}
128
129#if __GNUC__ < 2
130
131#define	inb(port)		inbv(port)
132#define	outb(port, data)	outbv(port, data)
133
134#else /* __GNUC >= 2 */
135
136/*
137 * The following complications are to get around gcc not having a
138 * constraint letter for the range 0..255.  We still put "d" in the
139 * constraint because "i" isn't a valid constraint when the port
140 * isn't constant.  This only matters for -O0 because otherwise
141 * the non-working version gets optimized away.
142 *
143 * Use an expression-statement instead of a conditional expression
144 * because gcc-2.6.0 would promote the operands of the conditional
145 * and produce poor code for "if ((inb(var) & const1) == const2)".
146 *
147 * The unnecessary test `(port) < 0x10000' is to generate a warning if
148 * the `port' has type u_short or smaller.  Such types are pessimal.
149 * This actually only works for signed types.  The range check is
150 * careful to avoid generating warnings.
151 */
152#define	inb(port) __extension__ ({					\
153	u_char	_data;							\
154	if (__builtin_constant_p(port) && ((port) & 0xffff) < 0x100	\
155	    && (port) < 0x10000)					\
156		_data = inbc(port);					\
157	else								\
158		_data = inbv(port);					\
159	_data; })
160
161#define	outb(port, data) (						\
162	__builtin_constant_p(port) && ((port) & 0xffff) < 0x100		\
163	&& (port) < 0x10000						\
164	? outbc(port, data) : outbv(port, data))
165
166static __inline u_char
167inbc(u_int port)
168{
169	u_char	data;
170
171	__asm __volatile("inb %1,%0" : "=a" (data) : "id" ((u_short)(port)));
172	return (data);
173}
174
175static __inline void
176outbc(u_int port, u_char data)
177{
178	__asm __volatile("outb %0,%1" : : "a" (data), "id" ((u_short)(port)));
179}
180
181#endif /* __GNUC <= 2 */
182
183static __inline u_char
184inbv(u_int port)
185{
186	u_char	data;
187	/*
188	 * We use %%dx and not %1 here because i/o is done at %dx and not at
189	 * %edx, while gcc generates inferior code (movw instead of movl)
190	 * if we tell it to load (u_short) port.
191	 */
192	__asm __volatile("inb %%dx,%0" : "=a" (data) : "d" (port));
193	return (data);
194}
195
196static __inline u_int
197inl(u_int port)
198{
199	u_int	data;
200
201	__asm __volatile("inl %%dx,%0" : "=a" (data) : "d" (port));
202	return (data);
203}
204
205static __inline void
206insb(u_int port, void *addr, size_t cnt)
207{
208	__asm __volatile("cld; rep; insb"
209			 : "+D" (addr), "+c" (cnt)
210			 : "d" (port)
211			 : "memory");
212}
213
214static __inline void
215insw(u_int port, void *addr, size_t cnt)
216{
217	__asm __volatile("cld; rep; insw"
218			 : "+D" (addr), "+c" (cnt)
219			 : "d" (port)
220			 : "memory");
221}
222
223static __inline void
224insl(u_int port, void *addr, size_t cnt)
225{
226	__asm __volatile("cld; rep; insl"
227			 : "+D" (addr), "+c" (cnt)
228			 : "d" (port)
229			 : "memory");
230}
231
232static __inline void
233invd(void)
234{
235	__asm __volatile("invd");
236}
237
238static __inline u_short
239inw(u_int port)
240{
241	u_short	data;
242
243	__asm __volatile("inw %%dx,%0" : "=a" (data) : "d" (port));
244	return (data);
245}
246
247static __inline void
248outbv(u_int port, u_char data)
249{
250	u_char	al;
251	/*
252	 * Use an unnecessary assignment to help gcc's register allocator.
253	 * This make a large difference for gcc-1.40 and a tiny difference
254	 * for gcc-2.6.0.  For gcc-1.40, al had to be ``asm("ax")'' for
255	 * best results.  gcc-2.6.0 can't handle this.
256	 */
257	al = data;
258	__asm __volatile("outb %0,%%dx" : : "a" (al), "d" (port));
259}
260
261static __inline void
262outl(u_int port, u_int data)
263{
264	/*
265	 * outl() and outw() aren't used much so we haven't looked at
266	 * possible micro-optimizations such as the unnecessary
267	 * assignment for them.
268	 */
269	__asm __volatile("outl %0,%%dx" : : "a" (data), "d" (port));
270}
271
272static __inline void
273outsb(u_int port, const void *addr, size_t cnt)
274{
275	__asm __volatile("cld; rep; outsb"
276			 : "+S" (addr), "+c" (cnt)
277			 : "d" (port));
278}
279
280static __inline void
281outsw(u_int port, const void *addr, size_t cnt)
282{
283	__asm __volatile("cld; rep; outsw"
284			 : "+S" (addr), "+c" (cnt)
285			 : "d" (port));
286}
287
288static __inline void
289outsl(u_int port, const void *addr, size_t cnt)
290{
291	__asm __volatile("cld; rep; outsl"
292			 : "+S" (addr), "+c" (cnt)
293			 : "d" (port));
294}
295
296static __inline void
297outw(u_int port, u_short data)
298{
299	__asm __volatile("outw %0,%%dx" : : "a" (data), "d" (port));
300}
301
302static __inline void
303ia32_pause(void)
304{
305	__asm __volatile("pause");
306}
307
308static __inline u_int
309read_eflags(void)
310{
311	u_int	ef;
312
313	__asm __volatile("pushfl; popl %0" : "=r" (ef));
314	return (ef);
315}
316
317static __inline u_int64_t
318rdmsr(u_int msr)
319{
320	u_int64_t rv;
321
322	__asm __volatile("rdmsr" : "=A" (rv) : "c" (msr));
323	return (rv);
324}
325
326static __inline u_int64_t
327rdpmc(u_int pmc)
328{
329	u_int64_t rv;
330
331	__asm __volatile("rdpmc" : "=A" (rv) : "c" (pmc));
332	return (rv);
333}
334
335static __inline u_int64_t
336rdtsc(void)
337{
338	u_int64_t rv;
339
340	__asm __volatile("rdtsc" : "=A" (rv));
341	return (rv);
342}
343
344static __inline void
345wbinvd(void)
346{
347	__asm __volatile("wbinvd");
348}
349
350static __inline void
351write_eflags(u_int ef)
352{
353	__asm __volatile("pushl %0; popfl" : : "r" (ef));
354}
355
356static __inline void
357wrmsr(u_int msr, u_int64_t newval)
358{
359	__asm __volatile("wrmsr" : : "A" (newval), "c" (msr));
360}
361
362static __inline void
363load_cr0(u_int data)
364{
365
366	__asm __volatile("movl %0,%%cr0" : : "r" (data));
367}
368
369static __inline u_int
370rcr0(void)
371{
372	u_int	data;
373
374	__asm __volatile("movl %%cr0,%0" : "=r" (data));
375	return (data);
376}
377
378static __inline u_int
379rcr2(void)
380{
381	u_int	data;
382
383	__asm __volatile("movl %%cr2,%0" : "=r" (data));
384	return (data);
385}
386
387static __inline void
388load_cr3(u_int data)
389{
390
391	__asm __volatile("movl %0,%%cr3" : : "r" (data) : "memory");
392}
393
394static __inline u_int
395rcr3(void)
396{
397	u_int	data;
398
399	__asm __volatile("movl %%cr3,%0" : "=r" (data));
400	return (data);
401}
402
403static __inline void
404load_cr4(u_int data)
405{
406	__asm __volatile("movl %0,%%cr4" : : "r" (data));
407}
408
409static __inline u_int
410rcr4(void)
411{
412	u_int	data;
413
414	__asm __volatile("movl %%cr4,%0" : "=r" (data));
415	return (data);
416}
417
418/*
419 * Global TLB flush (except for thise for pages marked PG_G)
420 */
421static __inline void
422invltlb(void)
423{
424
425	load_cr3(rcr3());
426}
427
428/*
429 * TLB flush for an individual page (even if it has PG_G).
430 * Only works on 486+ CPUs (i386 does not have PG_G).
431 */
432static __inline void
433invlpg(u_int addr)
434{
435
436	__asm __volatile("invlpg %0" : : "m" (*(char *)addr) : "memory");
437}
438
439static __inline u_int
440rfs(void)
441{
442	u_int sel;
443	__asm __volatile("movl %%fs,%0" : "=rm" (sel));
444	return (sel);
445}
446
447static __inline u_int
448rgs(void)
449{
450	u_int sel;
451	__asm __volatile("movl %%gs,%0" : "=rm" (sel));
452	return (sel);
453}
454
455static __inline void
456load_fs(u_int sel)
457{
458	__asm __volatile("movl %0,%%fs" : : "rm" (sel));
459}
460
461static __inline void
462load_gs(u_int sel)
463{
464	__asm __volatile("movl %0,%%gs" : : "rm" (sel));
465}
466
467static __inline void
468lidt(struct region_descriptor *addr)
469{
470	__asm __volatile("lidt (%0)" : : "r" (addr));
471}
472
473static __inline void
474lldt(u_short sel)
475{
476	__asm __volatile("lldt %0" : : "r" (sel));
477}
478
479static __inline void
480ltr(u_short sel)
481{
482	__asm __volatile("ltr %0" : : "r" (sel));
483}
484
485static __inline u_int
486rdr0(void)
487{
488	u_int	data;
489	__asm __volatile("movl %%dr0,%0" : "=r" (data));
490	return (data);
491}
492
493static __inline void
494load_dr0(u_int dr0)
495{
496	__asm __volatile("movl %0,%%dr0" : : "r" (dr0));
497}
498
499static __inline u_int
500rdr1(void)
501{
502	u_int	data;
503	__asm __volatile("movl %%dr1,%0" : "=r" (data));
504	return (data);
505}
506
507static __inline void
508load_dr1(u_int dr1)
509{
510	__asm __volatile("movl %0,%%dr1" : : "r" (dr1));
511}
512
513static __inline u_int
514rdr2(void)
515{
516	u_int	data;
517	__asm __volatile("movl %%dr2,%0" : "=r" (data));
518	return (data);
519}
520
521static __inline void
522load_dr2(u_int dr2)
523{
524	__asm __volatile("movl %0,%%dr2" : : "r" (dr2));
525}
526
527static __inline u_int
528rdr3(void)
529{
530	u_int	data;
531	__asm __volatile("movl %%dr3,%0" : "=r" (data));
532	return (data);
533}
534
535static __inline void
536load_dr3(u_int dr3)
537{
538	__asm __volatile("movl %0,%%dr3" : : "r" (dr3));
539}
540
541static __inline u_int
542rdr4(void)
543{
544	u_int	data;
545	__asm __volatile("movl %%dr4,%0" : "=r" (data));
546	return (data);
547}
548
549static __inline void
550load_dr4(u_int dr4)
551{
552	__asm __volatile("movl %0,%%dr4" : : "r" (dr4));
553}
554
555static __inline u_int
556rdr5(void)
557{
558	u_int	data;
559	__asm __volatile("movl %%dr5,%0" : "=r" (data));
560	return (data);
561}
562
563static __inline void
564load_dr5(u_int dr5)
565{
566	__asm __volatile("movl %0,%%dr5" : : "r" (dr5));
567}
568
569static __inline u_int
570rdr6(void)
571{
572	u_int	data;
573	__asm __volatile("movl %%dr6,%0" : "=r" (data));
574	return (data);
575}
576
577static __inline void
578load_dr6(u_int dr6)
579{
580	__asm __volatile("movl %0,%%dr6" : : "r" (dr6));
581}
582
583static __inline u_int
584rdr7(void)
585{
586	u_int	data;
587	__asm __volatile("movl %%dr7,%0" : "=r" (data));
588	return (data);
589}
590
591static __inline void
592load_dr7(u_int dr7)
593{
594	__asm __volatile("movl %0,%%dr7" : : "r" (dr7));
595}
596
597static __inline register_t
598intr_disable(void)
599{
600	register_t eflags;
601
602	eflags = read_eflags();
603	disable_intr();
604	return (eflags);
605}
606
607static __inline void
608intr_restore(register_t eflags)
609{
610	write_eflags(eflags);
611}
612
613#else /* !__GNUC__ */
614
615int	breakpoint(void);
616u_int	bsfl(u_int mask);
617u_int	bsrl(u_int mask);
618void	disable_intr(void);
619void	do_cpuid(u_int ax, u_int *p);
620void	enable_intr(void);
621void	halt(void);
622void	ia32_pause(void);
623u_char	inb(u_int port);
624u_int	inl(u_int port);
625void	insb(u_int port, void *addr, size_t cnt);
626void	insl(u_int port, void *addr, size_t cnt);
627void	insw(u_int port, void *addr, size_t cnt);
628register_t	intr_disable(void);
629void	intr_restore(register_t ef);
630void	invd(void);
631void	invlpg(u_int addr);
632void	invltlb(void);
633u_short	inw(u_int port);
634void	lidt(struct region_descriptor *addr);
635void	lldt(u_short sel);
636void	load_cr0(u_int cr0);
637void	load_cr3(u_int cr3);
638void	load_cr4(u_int cr4);
639void	load_dr0(u_int dr0);
640void	load_dr1(u_int dr1);
641void	load_dr2(u_int dr2);
642void	load_dr3(u_int dr3);
643void	load_dr4(u_int dr4);
644void	load_dr5(u_int dr5);
645void	load_dr6(u_int dr6);
646void	load_dr7(u_int dr7);
647void	load_fs(u_int sel);
648void	load_gs(u_int sel);
649void	ltr(u_short sel);
650void	outb(u_int port, u_char data);
651void	outl(u_int port, u_int data);
652void	outsb(u_int port, const void *addr, size_t cnt);
653void	outsl(u_int port, const void *addr, size_t cnt);
654void	outsw(u_int port, const void *addr, size_t cnt);
655void	outw(u_int port, u_short data);
656u_int	rcr0(void);
657u_int	rcr2(void);
658u_int	rcr3(void);
659u_int	rcr4(void);
660u_int64_t rdmsr(u_int msr);
661u_int64_t rdpmc(u_int pmc);
662u_int	rdr0(void);
663u_int	rdr1(void);
664u_int	rdr2(void);
665u_int	rdr3(void);
666u_int	rdr4(void);
667u_int	rdr5(void);
668u_int	rdr6(void);
669u_int	rdr7(void);
670u_int64_t rdtsc(void);
671u_int	read_eflags(void);
672u_int	rfs(void);
673u_int	rgs(void);
674void	wbinvd(void);
675void	write_eflags(u_int ef);
676void	wrmsr(u_int msr, u_int64_t newval);
677
678#endif	/* __GNUC__ */
679
680void    reset_dbregs(void);
681
682#endif /* !_MACHINE_CPUFUNC_H_ */
683