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