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