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