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: releng/7.3/sys/i386/include/cpufunc.h 203047 2010-01-26 20:58:09Z jhb $
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 struct region_descriptor;
46
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 #if defined(__GNUCLIKE_ASM) && defined(__CC_SUPPORTS___INLINE)
56
57 static __inline void
58 breakpoint(void)
59 {
60 __asm __volatile("int $3");
61 }
62
63 static __inline u_int
64 bsfl(u_int mask)
65 {
66 u_int result;
67
68 __asm __volatile("bsfl %1,%0" : "=r" (result) : "rm" (mask));
69 return (result);
70 }
71
72 static __inline u_int
73 bsrl(u_int mask)
74 {
75 u_int result;
76
77 __asm __volatile("bsrl %1,%0" : "=r" (result) : "rm" (mask));
78 return (result);
79 }
80
81 static __inline void
82 clflush(u_long addr)
83 {
84
85 __asm __volatile("clflush %0" : : "m" (*(char *)addr));
86 }
87
88 static __inline void
89 disable_intr(void)
90 {
91 __asm __volatile("cli" : : : "memory");
92 }
93
94 static __inline void
95 do_cpuid(u_int ax, u_int *p)
96 {
97 __asm __volatile("cpuid"
98 : "=a" (p[0]), "=b" (p[1]), "=c" (p[2]), "=d" (p[3])
99 : "" (ax));
100 }
101
102 static __inline void
103 cpuid_count(u_int ax, u_int cx, u_int *p)
104 {
105 __asm __volatile("cpuid"
106 : "=a" (p[0]), "=b" (p[1]), "=c" (p[2]), "=d" (p[3])
107 : "" (ax), "c" (cx));
108 }
109
110 static __inline void
111 enable_intr(void)
112 {
113 __asm __volatile("sti");
114 }
115
116 static __inline void
117 mfence(void)
118 {
119
120 __asm __volatile("mfence" : : : "memory");
121 }
122
123 #ifdef _KERNEL
124
125 #define HAVE_INLINE_FFS
126
127 static __inline int
128 ffs(int mask)
129 {
130 /*
131 * Note that gcc-2's builtin ffs would be used if we didn't declare
132 * this inline or turn off the builtin. The builtin is faster but
133 * broken in gcc-2.4.5 and slower but working in gcc-2.5 and later
134 * versions.
135 */
136 return (mask == 0 ? mask : (int)bsfl((u_int)mask) + 1);
137 }
138
139 #define HAVE_INLINE_FLS
140
141 static __inline int
142 fls(int mask)
143 {
144 return (mask == 0 ? mask : (int)bsrl((u_int)mask) + 1);
145 }
146
147 #endif /* _KERNEL */
148
149 static __inline void
150 halt(void)
151 {
152 __asm __volatile("hlt");
153 }
154
155 #if !defined(__GNUCLIKE_BUILTIN_CONSTANT_P) || __GNUCLIKE_ASM < 3
156
157 #define inb(port) inbv(port)
158 #define outb(port, data) outbv(port, data)
159
160 #else /* __GNUCLIKE_BUILTIN_CONSTANT_P && __GNUCLIKE_ASM >= 3 */
161
162 /*
163 * The following complications are to get around gcc not having a
164 * constraint letter for the range 0..255. We still put "d" in the
165 * constraint because "i" isn't a valid constraint when the port
166 * isn't constant. This only matters for -O0 because otherwise
167 * the non-working version gets optimized away.
168 *
169 * Use an expression-statement instead of a conditional expression
170 * because gcc-2.6.0 would promote the operands of the conditional
171 * and produce poor code for "if ((inb(var) & const1) == const2)".
172 *
173 * The unnecessary test `(port) < 0x10000' is to generate a warning if
174 * the `port' has type u_short or smaller. Such types are pessimal.
175 * This actually only works for signed types. The range check is
176 * careful to avoid generating warnings.
177 */
178 #define inb(port) __extension__ ({ \
179 u_char _data; \
180 if (__builtin_constant_p(port) && ((port) & 0xffff) < 0x100 \
181 && (port) < 0x10000) \
182 _data = inbc(port); \
183 else \
184 _data = inbv(port); \
185 _data; })
186
187 #define outb(port, data) ( \
188 __builtin_constant_p(port) && ((port) & 0xffff) < 0x100 \
189 && (port) < 0x10000 \
190 ? outbc(port, data) : outbv(port, data))
191
192 static __inline u_char
193 inbc(u_int port)
194 {
195 u_char data;
196
197 __asm __volatile("inb %1,%0" : "=a" (data) : "id" ((u_short)(port)));
198 return (data);
199 }
200
201 static __inline void
202 outbc(u_int port, u_char data)
203 {
204 __asm __volatile("outb %0,%1" : : "a" (data), "id" ((u_short)(port)));
205 }
206
207 #endif /* __GNUCLIKE_BUILTIN_CONSTANT_P && __GNUCLIKE_ASM >= 3*/
208
209 static __inline u_char
210 inbv(u_int port)
211 {
212 u_char data;
213 /*
214 * We use %%dx and not %1 here because i/o is done at %dx and not at
215 * %edx, while gcc generates inferior code (movw instead of movl)
216 * if we tell it to load (u_short) port.
217 */
218 __asm __volatile("inb %%dx,%0" : "=a" (data) : "d" (port));
219 return (data);
220 }
221
222 static __inline u_int
223 inl(u_int port)
224 {
225 u_int data;
226
227 __asm __volatile("inl %%dx,%0" : "=a" (data) : "d" (port));
228 return (data);
229 }
230
231 static __inline void
232 insb(u_int port, void *addr, size_t cnt)
233 {
234 __asm __volatile("cld; rep; insb"
235 : "+D" (addr), "+c" (cnt)
236 : "d" (port)
237 : "memory");
238 }
239
240 static __inline void
241 insw(u_int port, void *addr, size_t cnt)
242 {
243 __asm __volatile("cld; rep; insw"
244 : "+D" (addr), "+c" (cnt)
245 : "d" (port)
246 : "memory");
247 }
248
249 static __inline void
250 insl(u_int port, void *addr, size_t cnt)
251 {
252 __asm __volatile("cld; rep; insl"
253 : "+D" (addr), "+c" (cnt)
254 : "d" (port)
255 : "memory");
256 }
257
258 static __inline void
259 invd(void)
260 {
261 __asm __volatile("invd");
262 }
263
264 static __inline u_short
265 inw(u_int port)
266 {
267 u_short data;
268
269 __asm __volatile("inw %%dx,%0" : "=a" (data) : "d" (port));
270 return (data);
271 }
272
273 static __inline void
274 outbv(u_int port, u_char data)
275 {
276 u_char al;
277 /*
278 * Use an unnecessary assignment to help gcc's register allocator.
279 * This make a large difference for gcc-1.40 and a tiny difference
280 * for gcc-2.6.0. For gcc-1.40, al had to be ``asm("ax")'' for
281 * best results. gcc-2.6.0 can't handle this.
282 */
283 al = data;
284 __asm __volatile("outb %0,%%dx" : : "a" (al), "d" (port));
285 }
286
287 static __inline void
288 outl(u_int port, u_int data)
289 {
290 /*
291 * outl() and outw() aren't used much so we haven't looked at
292 * possible micro-optimizations such as the unnecessary
293 * assignment for them.
294 */
295 __asm __volatile("outl %0,%%dx" : : "a" (data), "d" (port));
296 }
297
298 static __inline void
299 outsb(u_int port, const void *addr, size_t cnt)
300 {
301 __asm __volatile("cld; rep; outsb"
302 : "+S" (addr), "+c" (cnt)
303 : "d" (port));
304 }
305
306 static __inline void
307 outsw(u_int port, const void *addr, size_t cnt)
308 {
309 __asm __volatile("cld; rep; outsw"
310 : "+S" (addr), "+c" (cnt)
311 : "d" (port));
312 }
313
314 static __inline void
315 outsl(u_int port, const void *addr, size_t cnt)
316 {
317 __asm __volatile("cld; rep; outsl"
318 : "+S" (addr), "+c" (cnt)
319 : "d" (port));
320 }
321
322 static __inline void
323 outw(u_int port, u_short data)
324 {
325 __asm __volatile("outw %0,%%dx" : : "a" (data), "d" (port));
326 }
327
328 static __inline void
329 ia32_pause(void)
330 {
331 __asm __volatile("pause");
332 }
333
334 static __inline u_int
335 read_eflags(void)
336 {
337 u_int ef;
338
339 __asm __volatile("pushfl; popl %0" : "=r" (ef));
340 return (ef);
341 }
342
343 static __inline uint64_t
344 rdmsr(u_int msr)
345 {
346 uint64_t rv;
347
348 __asm __volatile("rdmsr" : "=A" (rv) : "c" (msr));
349 return (rv);
350 }
351
352 static __inline uint64_t
353 rdpmc(u_int pmc)
354 {
355 uint64_t rv;
356
357 __asm __volatile("rdpmc" : "=A" (rv) : "c" (pmc));
358 return (rv);
359 }
360
361 static __inline uint64_t
362 rdtsc(void)
363 {
364 uint64_t rv;
365
366 __asm __volatile("rdtsc" : "=A" (rv));
367 return (rv);
368 }
369
370 static __inline void
371 wbinvd(void)
372 {
373 __asm __volatile("wbinvd");
374 }
375
376 static __inline void
377 write_eflags(u_int ef)
378 {
379 __asm __volatile("pushl %0; popfl" : : "r" (ef));
380 }
381
382 static __inline void
383 wrmsr(u_int msr, uint64_t newval)
384 {
385 __asm __volatile("wrmsr" : : "A" (newval), "c" (msr));
386 }
387
388 static __inline void
389 load_cr0(u_int data)
390 {
391
392 __asm __volatile("movl %0,%%cr0" : : "r" (data));
393 }
394
395 static __inline u_int
396 rcr0(void)
397 {
398 u_int data;
399
400 __asm __volatile("movl %%cr0,%0" : "=r" (data));
401 return (data);
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 void
414 load_cr3(u_int data)
415 {
416
417 __asm __volatile("movl %0,%%cr3" : : "r" (data) : "memory");
418 }
419
420 static __inline u_int
421 rcr3(void)
422 {
423 u_int data;
424
425 __asm __volatile("movl %%cr3,%0" : "=r" (data));
426 return (data);
427 }
428
429 static __inline void
430 load_cr4(u_int data)
431 {
432 __asm __volatile("movl %0,%%cr4" : : "r" (data));
433 }
434
435 static __inline u_int
436 rcr4(void)
437 {
438 u_int data;
439
440 __asm __volatile("movl %%cr4,%0" : "=r" (data));
441 return (data);
442 }
443
444 /*
445 * Global TLB flush (except for thise for pages marked PG_G)
446 */
447 static __inline void
448 invltlb(void)
449 {
450
451 load_cr3(rcr3());
452 }
453
454 /*
455 * TLB flush for an individual page (even if it has PG_G).
456 * Only works on 486+ CPUs (i386 does not have PG_G).
457 */
458 static __inline void
459 invlpg(u_int addr)
460 {
461
462 __asm __volatile("invlpg %0" : : "m" (*(char *)addr) : "memory");
463 }
464
465 static __inline u_int
466 rfs(void)
467 {
468 u_int sel;
469 __asm __volatile("movl %%fs,%0" : "=rm" (sel));
470 return (sel);
471 }
472
473 static __inline uint64_t
474 rgdt(void)
475 {
476 uint64_t gdtr;
477 __asm __volatile("sgdt %0" : "=m" (gdtr));
478 return (gdtr);
479 }
480
481 static __inline u_int
482 rgs(void)
483 {
484 u_int sel;
485 __asm __volatile("movl %%gs,%0" : "=rm" (sel));
486 return (sel);
487 }
488
489 static __inline uint64_t
490 ridt(void)
491 {
492 uint64_t idtr;
493 __asm __volatile("sidt %0" : "=m" (idtr));
494 return (idtr);
495 }
496
497 static __inline u_short
498 rldt(void)
499 {
500 u_short ldtr;
501 __asm __volatile("sldt %0" : "=g" (ldtr));
502 return (ldtr);
503 }
504
505 static __inline u_int
506 rss(void)
507 {
508 u_int sel;
509 __asm __volatile("movl %%ss,%0" : "=rm" (sel));
510 return (sel);
511 }
512
513 static __inline u_short
514 rtr(void)
515 {
516 u_short tr;
517 __asm __volatile("str %0" : "=g" (tr));
518 return (tr);
519 }
520
521 static __inline void
522 load_fs(u_int sel)
523 {
524 __asm __volatile("movl %0,%%fs" : : "rm" (sel));
525 }
526
527 static __inline void
528 load_gs(u_int sel)
529 {
530 __asm __volatile("movl %0,%%gs" : : "rm" (sel));
531 }
532
533 static __inline void
534 lidt(struct region_descriptor *addr)
535 {
536 __asm __volatile("lidt (%0)" : : "r" (addr));
537 }
538
539 static __inline void
540 lldt(u_short sel)
541 {
542 __asm __volatile("lldt %0" : : "r" (sel));
543 }
544
545 static __inline void
546 ltr(u_short sel)
547 {
548 __asm __volatile("ltr %0" : : "r" (sel));
549 }
550
551 static __inline u_int
552 rdr0(void)
553 {
554 u_int data;
555 __asm __volatile("movl %%dr0,%0" : "=r" (data));
556 return (data);
557 }
558
559 static __inline void
560 load_dr0(u_int dr0)
561 {
562 __asm __volatile("movl %0,%%dr0" : : "r" (dr0));
563 }
564
565 static __inline u_int
566 rdr1(void)
567 {
568 u_int data;
569 __asm __volatile("movl %%dr1,%0" : "=r" (data));
570 return (data);
571 }
572
573 static __inline void
574 load_dr1(u_int dr1)
575 {
576 __asm __volatile("movl %0,%%dr1" : : "r" (dr1));
577 }
578
579 static __inline u_int
580 rdr2(void)
581 {
582 u_int data;
583 __asm __volatile("movl %%dr2,%0" : "=r" (data));
584 return (data);
585 }
586
587 static __inline void
588 load_dr2(u_int dr2)
589 {
590 __asm __volatile("movl %0,%%dr2" : : "r" (dr2));
591 }
592
593 static __inline u_int
594 rdr3(void)
595 {
596 u_int data;
597 __asm __volatile("movl %%dr3,%0" : "=r" (data));
598 return (data);
599 }
600
601 static __inline void
602 load_dr3(u_int dr3)
603 {
604 __asm __volatile("movl %0,%%dr3" : : "r" (dr3));
605 }
606
607 static __inline u_int
608 rdr4(void)
609 {
610 u_int data;
611 __asm __volatile("movl %%dr4,%0" : "=r" (data));
612 return (data);
613 }
614
615 static __inline void
616 load_dr4(u_int dr4)
617 {
618 __asm __volatile("movl %0,%%dr4" : : "r" (dr4));
619 }
620
621 static __inline u_int
622 rdr5(void)
623 {
624 u_int data;
625 __asm __volatile("movl %%dr5,%0" : "=r" (data));
626 return (data);
627 }
628
629 static __inline void
630 load_dr5(u_int dr5)
631 {
632 __asm __volatile("movl %0,%%dr5" : : "r" (dr5));
633 }
634
635 static __inline u_int
636 rdr6(void)
637 {
638 u_int data;
639 __asm __volatile("movl %%dr6,%0" : "=r" (data));
640 return (data);
641 }
642
643 static __inline void
644 load_dr6(u_int dr6)
645 {
646 __asm __volatile("movl %0,%%dr6" : : "r" (dr6));
647 }
648
649 static __inline u_int
650 rdr7(void)
651 {
652 u_int data;
653 __asm __volatile("movl %%dr7,%0" : "=r" (data));
654 return (data);
655 }
656
657 static __inline void
658 load_dr7(u_int dr7)
659 {
660 __asm __volatile("movl %0,%%dr7" : : "r" (dr7));
661 }
662
663 static __inline u_char
664 read_cyrix_reg(u_char reg)
665 {
666 outb(0x22, reg);
667 return inb(0x23);
668 }
669
670 static __inline void
671 write_cyrix_reg(u_char reg, u_char data)
672 {
673 outb(0x22, reg);
674 outb(0x23, data);
675 }
676
677 static __inline register_t
678 intr_disable(void)
679 {
680 register_t eflags;
681
682 eflags = read_eflags();
683 disable_intr();
684 return (eflags);
685 }
686
687 static __inline void
688 intr_restore(register_t eflags)
689 {
690 write_eflags(eflags);
691 }
692
693 #else /* !(__GNUCLIKE_ASM && __CC_SUPPORTS___INLINE) */
694
695 int breakpoint(void);
696 u_int bsfl(u_int mask);
697 u_int bsrl(u_int mask);
698 void disable_intr(void);
699 void do_cpuid(u_int ax, u_int *p);
700 void enable_intr(void);
701 void halt(void);
702 void ia32_pause(void);
703 u_char inb(u_int port);
704 u_int inl(u_int port);
705 void insb(u_int port, void *addr, size_t cnt);
706 void insl(u_int port, void *addr, size_t cnt);
707 void insw(u_int port, void *addr, size_t cnt);
708 register_t intr_disable(void);
709 void intr_restore(register_t ef);
710 void invd(void);
711 void invlpg(u_int addr);
712 void invltlb(void);
713 u_short inw(u_int port);
714 void lidt(struct region_descriptor *addr);
715 void lldt(u_short sel);
716 void load_cr0(u_int cr0);
717 void load_cr3(u_int cr3);
718 void load_cr4(u_int cr4);
719 void load_dr0(u_int dr0);
720 void load_dr1(u_int dr1);
721 void load_dr2(u_int dr2);
722 void load_dr3(u_int dr3);
723 void load_dr4(u_int dr4);
724 void load_dr5(u_int dr5);
725 void load_dr6(u_int dr6);
726 void load_dr7(u_int dr7);
727 void load_fs(u_int sel);
728 void load_gs(u_int sel);
729 void ltr(u_short sel);
730 void outb(u_int port, u_char data);
731 void outl(u_int port, u_int data);
732 void outsb(u_int port, const void *addr, size_t cnt);
733 void outsl(u_int port, const void *addr, size_t cnt);
734 void outsw(u_int port, const void *addr, size_t cnt);
735 void outw(u_int port, u_short data);
736 u_int rcr0(void);
737 u_int rcr2(void);
738 u_int rcr3(void);
739 u_int rcr4(void);
740 uint64_t rdmsr(u_int msr);
741 uint64_t rdpmc(u_int pmc);
742 u_int rdr0(void);
743 u_int rdr1(void);
744 u_int rdr2(void);
745 u_int rdr3(void);
746 u_int rdr4(void);
747 u_int rdr5(void);
748 u_int rdr6(void);
749 u_int rdr7(void);
750 uint64_t rdtsc(void);
751 u_char read_cyrix_reg(u_char reg);
752 u_int read_eflags(void);
753 u_int rfs(void);
754 uint64_t rgdt(void);
755 u_int rgs(void);
756 uint64_t ridt(void);
757 u_short rldt(void);
758 u_short rtr(void);
759 void wbinvd(void);
760 void write_cyrix_reg(u_char reg, u_char data);
761 void write_eflags(u_int ef);
762 void wrmsr(u_int msr, uint64_t newval);
763
764 #endif /* __GNUCLIKE_ASM && __CC_SUPPORTS___INLINE */
765
766 void reset_dbregs(void);
767
768 #ifdef _KERNEL
769 int rdmsr_safe(u_int msr, uint64_t *val);
770 int wrmsr_safe(u_int msr, uint64_t newval);
771 #endif
772
773 #endif /* !_MACHINE_CPUFUNC_H_ */
Cache object: dd339c0dea3168eaf3faab3fdc3b4094
|