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