]> CyberLeo.Net >> Repos - FreeBSD/stable/8.git/blob - sys/i386/include/cpufunc.h
MFC r240520:
[FreeBSD/stable/8.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  * 4. Neither the name of the University nor the names of its contributors
14  *    may be used to endorse or promote products derived from this software
15  *    without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  *
29  * $FreeBSD$
30  */
31
32 /*
33  * Functions to provide access to special i386 instructions.
34  * This in included in sys/systm.h, and that file should be
35  * used in preference to this.
36  */
37
38 #ifndef _MACHINE_CPUFUNC_H_
39 #define _MACHINE_CPUFUNC_H_
40
41 #ifndef _SYS_CDEFS_H_
42 #error this file needs sys/cdefs.h as a prerequisite
43 #endif
44
45 #ifdef XEN
46 extern void xen_cli(void);
47 extern void xen_sti(void);
48 extern u_int xen_rcr2(void);
49 extern void xen_load_cr3(u_int data);
50 extern void xen_tlb_flush(void);
51 extern void xen_invlpg(u_int addr);
52 extern void write_eflags(u_int eflags);
53 extern u_int read_eflags(void);
54 #endif
55
56 struct region_descriptor;
57
58 #define readb(va)       (*(volatile u_int8_t *) (va))
59 #define readw(va)       (*(volatile u_int16_t *) (va))
60 #define readl(va)       (*(volatile u_int32_t *) (va))
61
62 #define writeb(va, d)   (*(volatile u_int8_t *) (va) = (d))
63 #define writew(va, d)   (*(volatile u_int16_t *) (va) = (d))
64 #define writel(va, d)   (*(volatile u_int32_t *) (va) = (d))
65
66 #if defined(__GNUCLIKE_ASM) && defined(__CC_SUPPORTS___INLINE)
67
68 static __inline void
69 breakpoint(void)
70 {
71         __asm __volatile("int $3");
72 }
73
74 static __inline u_int
75 bsfl(u_int mask)
76 {
77         u_int   result;
78
79         __asm("bsfl %1,%0" : "=r" (result) : "rm" (mask) : "cc");
80         return (result);
81 }
82
83 static __inline u_int
84 bsrl(u_int mask)
85 {
86         u_int   result;
87
88         __asm("bsrl %1,%0" : "=r" (result) : "rm" (mask) : "cc");
89         return (result);
90 }
91
92 static __inline void
93 clflush(u_long addr)
94 {
95
96         __asm __volatile("clflush %0" : : "m" (*(char *)addr));
97 }
98
99 static __inline void
100 disable_intr(void)
101 {
102 #ifdef XEN
103         xen_cli();
104 #else   
105         __asm __volatile("cli" : : : "memory");
106 #endif
107 }
108
109 static __inline void
110 do_cpuid(u_int ax, u_int *p)
111 {
112         __asm __volatile("cpuid"
113                          : "=a" (p[0]), "=b" (p[1]), "=c" (p[2]), "=d" (p[3])
114                          :  "0" (ax));
115 }
116
117 static __inline void
118 cpuid_count(u_int ax, u_int cx, u_int *p)
119 {
120         __asm __volatile("cpuid"
121                          : "=a" (p[0]), "=b" (p[1]), "=c" (p[2]), "=d" (p[3])
122                          :  "0" (ax), "c" (cx));
123 }
124
125 static __inline void
126 enable_intr(void)
127 {
128 #ifdef XEN
129         xen_sti();
130 #else
131         __asm __volatile("sti");
132 #endif
133 }
134
135 static __inline void
136 cpu_monitor(const void *addr, int extensions, int hints)
137 {
138         __asm __volatile("monitor;"
139             : :"a" (addr), "c" (extensions), "d"(hints));
140 }
141
142 static __inline void
143 cpu_mwait(int extensions, int hints)
144 {
145         __asm __volatile("mwait;" : :"a" (hints), "c" (extensions));
146 }
147
148 static __inline void
149 lfence(void)
150 {
151
152         __asm __volatile("lfence" : : : "memory");
153 }
154
155 static __inline void
156 mfence(void)
157 {
158
159         __asm __volatile("mfence" : : : "memory");
160 }
161
162 #ifdef _KERNEL
163
164 #define HAVE_INLINE_FFS
165
166 static __inline int
167 ffs(int mask)
168 {
169         /*
170          * Note that gcc-2's builtin ffs would be used if we didn't declare
171          * this inline or turn off the builtin.  The builtin is faster but
172          * broken in gcc-2.4.5 and slower but working in gcc-2.5 and later
173          * versions.
174          */
175          return (mask == 0 ? mask : (int)bsfl((u_int)mask) + 1);
176 }
177
178 #define HAVE_INLINE_FLS
179
180 static __inline int
181 fls(int mask)
182 {
183         return (mask == 0 ? mask : (int)bsrl((u_int)mask) + 1);
184 }
185
186 #endif /* _KERNEL */
187
188 static __inline void
189 halt(void)
190 {
191         __asm __volatile("hlt");
192 }
193
194 static __inline u_char
195 inb(u_int port)
196 {
197         u_char  data;
198
199         __asm volatile("inb %w1, %0" : "=a" (data) : "Nd" (port));
200         return (data);
201 }
202
203 static __inline u_int
204 inl(u_int port)
205 {
206         u_int   data;
207
208         __asm volatile("inl %w1, %0" : "=a" (data) : "Nd" (port));
209         return (data);
210 }
211
212 static __inline void
213 insb(u_int port, void *addr, size_t cnt)
214 {
215         __asm __volatile("cld; rep; insb"
216                          : "+D" (addr), "+c" (cnt)
217                          : "d" (port)
218                          : "memory");
219 }
220
221 static __inline void
222 insw(u_int port, void *addr, size_t cnt)
223 {
224         __asm __volatile("cld; rep; insw"
225                          : "+D" (addr), "+c" (cnt)
226                          : "d" (port)
227                          : "memory");
228 }
229
230 static __inline void
231 insl(u_int port, void *addr, size_t cnt)
232 {
233         __asm __volatile("cld; rep; insl"
234                          : "+D" (addr), "+c" (cnt)
235                          : "d" (port)
236                          : "memory");
237 }
238
239 static __inline void
240 invd(void)
241 {
242         __asm __volatile("invd");
243 }
244
245 static __inline u_short
246 inw(u_int port)
247 {
248         u_short data;
249
250         __asm volatile("inw %w1, %0" : "=a" (data) : "Nd" (port));
251         return (data);
252 }
253
254 static __inline void
255 outb(u_int port, u_char data)
256 {
257         __asm __volatile("outb %0, %w1" : : "a" (data), "Nd" (port));
258 }
259
260 static __inline void
261 outl(u_int port, u_int data)
262 {
263         __asm volatile("outl %0, %w1" : : "a" (data), "Nd" (port));
264 }
265
266 static __inline void
267 outsb(u_int port, const void *addr, size_t cnt)
268 {
269         __asm __volatile("cld; rep; outsb"
270                          : "+S" (addr), "+c" (cnt)
271                          : "d" (port));
272 }
273
274 static __inline void
275 outsw(u_int port, const void *addr, size_t cnt)
276 {
277         __asm __volatile("cld; rep; outsw"
278                          : "+S" (addr), "+c" (cnt)
279                          : "d" (port));
280 }
281
282 static __inline void
283 outsl(u_int port, const void *addr, size_t cnt)
284 {
285         __asm __volatile("cld; rep; outsl"
286                          : "+S" (addr), "+c" (cnt)
287                          : "d" (port));
288 }
289
290 static __inline void
291 outw(u_int port, u_short data)
292 {
293         __asm volatile("outw %0, %w1" : : "a" (data), "Nd" (port));
294 }
295
296 static __inline void
297 ia32_pause(void)
298 {
299         __asm __volatile("pause");
300 }
301
302 static __inline u_int
303 #ifdef XEN
304 _read_eflags(void)
305 #else   
306 read_eflags(void)
307 #endif
308 {
309         u_int   ef;
310
311         __asm __volatile("pushfl; popl %0" : "=r" (ef));
312         return (ef);
313 }
314
315 static __inline uint64_t
316 rdmsr(u_int msr)
317 {
318         uint64_t rv;
319
320         __asm __volatile("rdmsr" : "=A" (rv) : "c" (msr));
321         return (rv);
322 }
323
324 static __inline uint64_t
325 rdpmc(u_int pmc)
326 {
327         uint64_t rv;
328
329         __asm __volatile("rdpmc" : "=A" (rv) : "c" (pmc));
330         return (rv);
331 }
332
333 static __inline uint64_t
334 rdtsc(void)
335 {
336         uint64_t rv;
337
338         __asm __volatile("rdtsc" : "=A" (rv));
339         return (rv);
340 }
341
342 static __inline void
343 wbinvd(void)
344 {
345         __asm __volatile("wbinvd");
346 }
347
348 static __inline void
349 #ifdef XEN
350 _write_eflags(u_int ef)
351 #else
352 write_eflags(u_int ef)
353 #endif
354 {
355         __asm __volatile("pushl %0; popfl" : : "r" (ef));
356 }
357
358 static __inline void
359 wrmsr(u_int msr, uint64_t newval)
360 {
361         __asm __volatile("wrmsr" : : "A" (newval), "c" (msr));
362 }
363
364 static __inline void
365 load_cr0(u_int data)
366 {
367
368         __asm __volatile("movl %0,%%cr0" : : "r" (data));
369 }
370
371 static __inline u_int
372 rcr0(void)
373 {
374         u_int   data;
375
376         __asm __volatile("movl %%cr0,%0" : "=r" (data));
377         return (data);
378 }
379
380 static __inline u_int
381 rcr2(void)
382 {
383         u_int   data;
384
385 #ifdef XEN
386         return (xen_rcr2());
387 #endif
388         __asm __volatile("movl %%cr2,%0" : "=r" (data));
389         return (data);
390 }
391
392 static __inline void
393 load_cr3(u_int data)
394 {
395 #ifdef XEN
396         xen_load_cr3(data);
397 #else
398         __asm __volatile("movl %0,%%cr3" : : "r" (data) : "memory");
399 #endif
400 }
401
402 static __inline u_int
403 rcr3(void)
404 {
405         u_int   data;
406
407         __asm __volatile("movl %%cr3,%0" : "=r" (data));
408         return (data);
409 }
410
411 static __inline void
412 load_cr4(u_int data)
413 {
414         __asm __volatile("movl %0,%%cr4" : : "r" (data));
415 }
416
417 static __inline u_int
418 rcr4(void)
419 {
420         u_int   data;
421
422         __asm __volatile("movl %%cr4,%0" : "=r" (data));
423         return (data);
424 }
425
426 /*
427  * Global TLB flush (except for thise for pages marked PG_G)
428  */
429 static __inline void
430 invltlb(void)
431 {
432 #ifdef XEN
433         xen_tlb_flush();
434 #else   
435         load_cr3(rcr3());
436 #endif
437 }
438
439 /*
440  * TLB flush for an individual page (even if it has PG_G).
441  * Only works on 486+ CPUs (i386 does not have PG_G).
442  */
443 static __inline void
444 invlpg(u_int addr)
445 {
446
447 #ifdef XEN
448         xen_invlpg(addr);
449 #else
450         __asm __volatile("invlpg %0" : : "m" (*(char *)addr) : "memory");
451 #endif
452 }
453
454 static __inline u_int
455 rfs(void)
456 {
457         u_int sel;
458         __asm __volatile("mov %%fs,%0" : "=rm" (sel));
459         return (sel);
460 }
461
462 static __inline uint64_t
463 rgdt(void)
464 {
465         uint64_t gdtr;
466         __asm __volatile("sgdt %0" : "=m" (gdtr));
467         return (gdtr);
468 }
469
470 static __inline u_int
471 rgs(void)
472 {
473         u_int sel;
474         __asm __volatile("mov %%gs,%0" : "=rm" (sel));
475         return (sel);
476 }
477
478 static __inline uint64_t
479 ridt(void)
480 {
481         uint64_t idtr;
482         __asm __volatile("sidt %0" : "=m" (idtr));
483         return (idtr);
484 }
485
486 static __inline u_short
487 rldt(void)
488 {
489         u_short ldtr;
490         __asm __volatile("sldt %0" : "=g" (ldtr));
491         return (ldtr);
492 }
493
494 static __inline u_int
495 rss(void)
496 {
497         u_int sel;
498         __asm __volatile("mov %%ss,%0" : "=rm" (sel));
499         return (sel);
500 }
501
502 static __inline u_short
503 rtr(void)
504 {
505         u_short tr;
506         __asm __volatile("str %0" : "=g" (tr));
507         return (tr);
508 }
509
510 static __inline void
511 load_fs(u_int sel)
512 {
513         __asm __volatile("mov %0,%%fs" : : "rm" (sel));
514 }
515
516 static __inline void
517 load_gs(u_int sel)
518 {
519         __asm __volatile("mov %0,%%gs" : : "rm" (sel));
520 }
521
522 static __inline void
523 lidt(struct region_descriptor *addr)
524 {
525         __asm __volatile("lidt (%0)" : : "r" (addr));
526 }
527
528 static __inline void
529 lldt(u_short sel)
530 {
531         __asm __volatile("lldt %0" : : "r" (sel));
532 }
533
534 static __inline void
535 ltr(u_short sel)
536 {
537         __asm __volatile("ltr %0" : : "r" (sel));
538 }
539
540 static __inline u_int
541 rdr0(void)
542 {
543         u_int   data;
544         __asm __volatile("movl %%dr0,%0" : "=r" (data));
545         return (data);
546 }
547
548 static __inline void
549 load_dr0(u_int dr0)
550 {
551         __asm __volatile("movl %0,%%dr0" : : "r" (dr0));
552 }
553
554 static __inline u_int
555 rdr1(void)
556 {
557         u_int   data;
558         __asm __volatile("movl %%dr1,%0" : "=r" (data));
559         return (data);
560 }
561
562 static __inline void
563 load_dr1(u_int dr1)
564 {
565         __asm __volatile("movl %0,%%dr1" : : "r" (dr1));
566 }
567
568 static __inline u_int
569 rdr2(void)
570 {
571         u_int   data;
572         __asm __volatile("movl %%dr2,%0" : "=r" (data));
573         return (data);
574 }
575
576 static __inline void
577 load_dr2(u_int dr2)
578 {
579         __asm __volatile("movl %0,%%dr2" : : "r" (dr2));
580 }
581
582 static __inline u_int
583 rdr3(void)
584 {
585         u_int   data;
586         __asm __volatile("movl %%dr3,%0" : "=r" (data));
587         return (data);
588 }
589
590 static __inline void
591 load_dr3(u_int dr3)
592 {
593         __asm __volatile("movl %0,%%dr3" : : "r" (dr3));
594 }
595
596 static __inline u_int
597 rdr4(void)
598 {
599         u_int   data;
600         __asm __volatile("movl %%dr4,%0" : "=r" (data));
601         return (data);
602 }
603
604 static __inline void
605 load_dr4(u_int dr4)
606 {
607         __asm __volatile("movl %0,%%dr4" : : "r" (dr4));
608 }
609
610 static __inline u_int
611 rdr5(void)
612 {
613         u_int   data;
614         __asm __volatile("movl %%dr5,%0" : "=r" (data));
615         return (data);
616 }
617
618 static __inline void
619 load_dr5(u_int dr5)
620 {
621         __asm __volatile("movl %0,%%dr5" : : "r" (dr5));
622 }
623
624 static __inline u_int
625 rdr6(void)
626 {
627         u_int   data;
628         __asm __volatile("movl %%dr6,%0" : "=r" (data));
629         return (data);
630 }
631
632 static __inline void
633 load_dr6(u_int dr6)
634 {
635         __asm __volatile("movl %0,%%dr6" : : "r" (dr6));
636 }
637
638 static __inline u_int
639 rdr7(void)
640 {
641         u_int   data;
642         __asm __volatile("movl %%dr7,%0" : "=r" (data));
643         return (data);
644 }
645
646 static __inline void
647 load_dr7(u_int dr7)
648 {
649         __asm __volatile("movl %0,%%dr7" : : "r" (dr7));
650 }
651
652 static __inline u_char
653 read_cyrix_reg(u_char reg)
654 {
655         outb(0x22, reg);
656         return inb(0x23);
657 }
658
659 static __inline void
660 write_cyrix_reg(u_char reg, u_char data)
661 {
662         outb(0x22, reg);
663         outb(0x23, data);
664 }
665
666 static __inline register_t
667 intr_disable(void)
668 {
669         register_t eflags;
670
671         eflags = read_eflags();
672         disable_intr();
673         return (eflags);
674 }
675
676 static __inline void
677 intr_restore(register_t eflags)
678 {
679         write_eflags(eflags);
680 }
681
682 #else /* !(__GNUCLIKE_ASM && __CC_SUPPORTS___INLINE) */
683
684 int     breakpoint(void);
685 u_int   bsfl(u_int mask);
686 u_int   bsrl(u_int mask);
687 void    disable_intr(void);
688 void    do_cpuid(u_int ax, u_int *p);
689 void    enable_intr(void);
690 void    halt(void);
691 void    ia32_pause(void);
692 u_char  inb(u_int port);
693 u_int   inl(u_int port);
694 void    insb(u_int port, void *addr, size_t cnt);
695 void    insl(u_int port, void *addr, size_t cnt);
696 void    insw(u_int port, void *addr, size_t cnt);
697 register_t      intr_disable(void);
698 void    intr_restore(register_t ef);
699 void    invd(void);
700 void    invlpg(u_int addr);
701 void    invltlb(void);
702 u_short inw(u_int port);
703 void    lidt(struct region_descriptor *addr);
704 void    lldt(u_short sel);
705 void    load_cr0(u_int cr0);
706 void    load_cr3(u_int cr3);
707 void    load_cr4(u_int cr4);
708 void    load_dr0(u_int dr0);
709 void    load_dr1(u_int dr1);
710 void    load_dr2(u_int dr2);
711 void    load_dr3(u_int dr3);
712 void    load_dr4(u_int dr4);
713 void    load_dr5(u_int dr5);
714 void    load_dr6(u_int dr6);
715 void    load_dr7(u_int dr7);
716 void    load_fs(u_int sel);
717 void    load_gs(u_int sel);
718 void    ltr(u_short sel);
719 void    outb(u_int port, u_char data);
720 void    outl(u_int port, u_int data);
721 void    outsb(u_int port, const void *addr, size_t cnt);
722 void    outsl(u_int port, const void *addr, size_t cnt);
723 void    outsw(u_int port, const void *addr, size_t cnt);
724 void    outw(u_int port, u_short data);
725 u_int   rcr0(void);
726 u_int   rcr2(void);
727 u_int   rcr3(void);
728 u_int   rcr4(void);
729 uint64_t rdmsr(u_int msr);
730 uint64_t rdpmc(u_int pmc);
731 u_int   rdr0(void);
732 u_int   rdr1(void);
733 u_int   rdr2(void);
734 u_int   rdr3(void);
735 u_int   rdr4(void);
736 u_int   rdr5(void);
737 u_int   rdr6(void);
738 u_int   rdr7(void);
739 uint64_t rdtsc(void);
740 u_char  read_cyrix_reg(u_char reg);
741 u_int   read_eflags(void);
742 u_int   rfs(void);
743 uint64_t rgdt(void);
744 u_int   rgs(void);
745 uint64_t ridt(void);
746 u_short rldt(void);
747 u_short rtr(void);
748 void    wbinvd(void);
749 void    write_cyrix_reg(u_char reg, u_char data);
750 void    write_eflags(u_int ef);
751 void    wrmsr(u_int msr, uint64_t newval);
752
753 #endif  /* __GNUCLIKE_ASM && __CC_SUPPORTS___INLINE */
754
755 void    reset_dbregs(void);
756
757 #ifdef _KERNEL
758 int     rdmsr_safe(u_int msr, uint64_t *val);
759 int     wrmsr_safe(u_int msr, uint64_t newval);
760 #endif
761
762 #endif /* !_MACHINE_CPUFUNC_H_ */