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