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