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