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