xref: /haiku/src/libs/compat/freebsd_network/compat/machine/x86/cpufunc.h (revision 97a29cc79686fa6b8753542ef37bb49680a4a60f)
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