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