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