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