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