xref: /freebsd/sys/amd64/include/cpufunc.h (revision 19261079b74319502c6ffa1249920079f0f69a72)
1 /*-
2  * SPDX-License-Identifier: BSD-3-Clause
3  *
4  * Copyright (c) 2003 Peter Wemm.
5  * Copyright (c) 1993 The Regents of the University of California.
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  * 3. Neither the name of the University nor the names of its contributors
17  *    may be used to endorse or promote products derived from this software
18  *    without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30  * SUCH DAMAGE.
31  *
32  * $FreeBSD$
33  */
34 
35 /*
36  * Functions to provide access to special i386 instructions.
37  * This in included in sys/systm.h, and that file should be
38  * used in preference to this.
39  */
40 
41 #ifndef _MACHINE_CPUFUNC_H_
42 #define	_MACHINE_CPUFUNC_H_
43 
44 #ifndef _SYS_CDEFS_H_
45 #error this file needs sys/cdefs.h as a prerequisite
46 #endif
47 
48 struct region_descriptor;
49 
50 #define readb(va)	(*(volatile uint8_t *) (va))
51 #define readw(va)	(*(volatile uint16_t *) (va))
52 #define readl(va)	(*(volatile uint32_t *) (va))
53 #define readq(va)	(*(volatile uint64_t *) (va))
54 
55 #define writeb(va, d)	(*(volatile uint8_t *) (va) = (d))
56 #define writew(va, d)	(*(volatile uint16_t *) (va) = (d))
57 #define writel(va, d)	(*(volatile uint32_t *) (va) = (d))
58 #define writeq(va, d)	(*(volatile uint64_t *) (va) = (d))
59 
60 #if defined(__GNUCLIKE_ASM) && defined(__CC_SUPPORTS___INLINE)
61 
62 static __inline void
63 breakpoint(void)
64 {
65 	__asm __volatile("int $3");
66 }
67 
68 #define	bsfl(mask)	__builtin_ctz(mask)
69 
70 #define	bsfq(mask)	__builtin_ctzl(mask)
71 
72 #define	bsrl(mask)	(__builtin_clz(mask) ^ 0x1f)
73 
74 #define	bsrq(mask)	(__builtin_clzl(mask) ^ 0x3f)
75 
76 static __inline void
77 clflush(u_long addr)
78 {
79 
80 	__asm __volatile("clflush %0" : : "m" (*(char *)addr));
81 }
82 
83 static __inline void
84 clflushopt(u_long addr)
85 {
86 
87 	__asm __volatile(".byte 0x66;clflush %0" : : "m" (*(char *)addr));
88 }
89 
90 static __inline void
91 clwb(u_long addr)
92 {
93 
94 	__asm __volatile("clwb %0" : : "m" (*(char *)addr));
95 }
96 
97 static __inline void
98 clts(void)
99 {
100 
101 	__asm __volatile("clts");
102 }
103 
104 static __inline void
105 disable_intr(void)
106 {
107 	__asm __volatile("cli" : : : "memory");
108 }
109 
110 static __inline void
111 do_cpuid(u_int ax, u_int *p)
112 {
113 	__asm __volatile("cpuid"
114 			 : "=a" (p[0]), "=b" (p[1]), "=c" (p[2]), "=d" (p[3])
115 			 :  "0" (ax));
116 }
117 
118 static __inline void
119 cpuid_count(u_int ax, u_int cx, u_int *p)
120 {
121 	__asm __volatile("cpuid"
122 			 : "=a" (p[0]), "=b" (p[1]), "=c" (p[2]), "=d" (p[3])
123 			 :  "0" (ax), "c" (cx));
124 }
125 
126 static __inline void
127 enable_intr(void)
128 {
129 	__asm __volatile("sti");
130 }
131 
132 #ifdef _KERNEL
133 
134 #define	HAVE_INLINE_FFS
135 #define	ffs(x)		__builtin_ffs(x)
136 
137 #define	HAVE_INLINE_FFSL
138 #define	ffsl(x)		__builtin_ffsl(x)
139 
140 #define	HAVE_INLINE_FFSLL
141 #define	ffsll(x)	__builtin_ffsll(x)
142 
143 #define	HAVE_INLINE_FLS
144 
145 static __inline __pure2 int
146 fls(int mask)
147 {
148 	return (mask == 0 ? mask : (int)bsrl((u_int)mask) + 1);
149 }
150 
151 #define	HAVE_INLINE_FLSL
152 
153 static __inline __pure2 int
154 flsl(long mask)
155 {
156 	return (mask == 0 ? mask : (int)bsrq((u_long)mask) + 1);
157 }
158 
159 #define	HAVE_INLINE_FLSLL
160 
161 static __inline __pure2 int
162 flsll(long long mask)
163 {
164 	return (flsl((long)mask));
165 }
166 
167 #endif /* _KERNEL */
168 
169 static __inline void
170 halt(void)
171 {
172 	__asm __volatile("hlt");
173 }
174 
175 static __inline u_char
176 inb(u_int port)
177 {
178 	u_char	data;
179 
180 	__asm __volatile("inb %w1, %0" : "=a" (data) : "Nd" (port));
181 	return (data);
182 }
183 
184 static __inline u_int
185 inl(u_int port)
186 {
187 	u_int	data;
188 
189 	__asm __volatile("inl %w1, %0" : "=a" (data) : "Nd" (port));
190 	return (data);
191 }
192 
193 static __inline void
194 insb(u_int port, void *addr, size_t count)
195 {
196 	__asm __volatile("rep; insb"
197 			 : "+D" (addr), "+c" (count)
198 			 : "d" (port)
199 			 : "memory");
200 }
201 
202 static __inline void
203 insw(u_int port, void *addr, size_t count)
204 {
205 	__asm __volatile("rep; insw"
206 			 : "+D" (addr), "+c" (count)
207 			 : "d" (port)
208 			 : "memory");
209 }
210 
211 static __inline void
212 insl(u_int port, void *addr, size_t count)
213 {
214 	__asm __volatile("rep; insl"
215 			 : "+D" (addr), "+c" (count)
216 			 : "d" (port)
217 			 : "memory");
218 }
219 
220 static __inline void
221 invd(void)
222 {
223 	__asm __volatile("invd");
224 }
225 
226 static __inline u_short
227 inw(u_int port)
228 {
229 	u_short	data;
230 
231 	__asm __volatile("inw %w1, %0" : "=a" (data) : "Nd" (port));
232 	return (data);
233 }
234 
235 static __inline void
236 outb(u_int port, u_char data)
237 {
238 	__asm __volatile("outb %0, %w1" : : "a" (data), "Nd" (port));
239 }
240 
241 static __inline void
242 outl(u_int port, u_int data)
243 {
244 	__asm __volatile("outl %0, %w1" : : "a" (data), "Nd" (port));
245 }
246 
247 static __inline void
248 outsb(u_int port, const void *addr, size_t count)
249 {
250 	__asm __volatile("rep; outsb"
251 			 : "+S" (addr), "+c" (count)
252 			 : "d" (port));
253 }
254 
255 static __inline void
256 outsw(u_int port, const void *addr, size_t count)
257 {
258 	__asm __volatile("rep; outsw"
259 			 : "+S" (addr), "+c" (count)
260 			 : "d" (port));
261 }
262 
263 static __inline void
264 outsl(u_int port, const void *addr, size_t count)
265 {
266 	__asm __volatile("rep; outsl"
267 			 : "+S" (addr), "+c" (count)
268 			 : "d" (port));
269 }
270 
271 static __inline void
272 outw(u_int port, u_short data)
273 {
274 	__asm __volatile("outw %0, %w1" : : "a" (data), "Nd" (port));
275 }
276 
277 static __inline u_long
278 popcntq(u_long mask)
279 {
280 	u_long result;
281 
282 	__asm __volatile("popcntq %1,%0" : "=r" (result) : "rm" (mask));
283 	return (result);
284 }
285 
286 static __inline void
287 lfence(void)
288 {
289 
290 	__asm __volatile("lfence" : : : "memory");
291 }
292 
293 static __inline void
294 mfence(void)
295 {
296 
297 	__asm __volatile("mfence" : : : "memory");
298 }
299 
300 static __inline void
301 sfence(void)
302 {
303 
304 	__asm __volatile("sfence" : : : "memory");
305 }
306 
307 static __inline void
308 ia32_pause(void)
309 {
310 	__asm __volatile("pause");
311 }
312 
313 static __inline u_long
314 read_rflags(void)
315 {
316 	u_long	rf;
317 
318 	__asm __volatile("pushfq; popq %0" : "=r" (rf));
319 	return (rf);
320 }
321 
322 static __inline uint64_t
323 rdmsr(u_int msr)
324 {
325 	uint32_t low, high;
326 
327 	__asm __volatile("rdmsr" : "=a" (low), "=d" (high) : "c" (msr));
328 	return (low | ((uint64_t)high << 32));
329 }
330 
331 static __inline uint32_t
332 rdmsr32(u_int msr)
333 {
334 	uint32_t low;
335 
336 	__asm __volatile("rdmsr" : "=a" (low) : "c" (msr) : "rdx");
337 	return (low);
338 }
339 
340 static __inline uint64_t
341 rdpmc(u_int pmc)
342 {
343 	uint32_t low, high;
344 
345 	__asm __volatile("rdpmc" : "=a" (low), "=d" (high) : "c" (pmc));
346 	return (low | ((uint64_t)high << 32));
347 }
348 
349 static __inline uint64_t
350 rdtsc(void)
351 {
352 	uint32_t low, high;
353 
354 	__asm __volatile("rdtsc" : "=a" (low), "=d" (high));
355 	return (low | ((uint64_t)high << 32));
356 }
357 
358 static __inline uint64_t
359 rdtsc_ordered_lfence(void)
360 {
361 	lfence();
362 	return (rdtsc());
363 }
364 
365 static __inline uint64_t
366 rdtsc_ordered_mfence(void)
367 {
368 	mfence();
369 	return (rdtsc());
370 }
371 
372 static __inline uint64_t
373 rdtscp(void)
374 {
375 	uint32_t low, high;
376 
377 	__asm __volatile("rdtscp" : "=a" (low), "=d" (high) : : "ecx");
378 	return (low | ((uint64_t)high << 32));
379 }
380 
381 static __inline uint64_t
382 rdtscp_aux(uint32_t *aux)
383 {
384 	uint32_t low, high;
385 
386 	__asm __volatile("rdtscp" : "=a" (low), "=d" (high), "=c" (*aux));
387 	return (low | ((uint64_t)high << 32));
388 }
389 
390 static __inline uint32_t
391 rdtsc32(void)
392 {
393 	uint32_t rv;
394 
395 	__asm __volatile("rdtsc" : "=a" (rv) : : "edx");
396 	return (rv);
397 }
398 
399 static __inline uint32_t
400 rdtscp32(void)
401 {
402 	uint32_t rv;
403 
404 	__asm __volatile("rdtscp" : "=a" (rv) : : "ecx", "edx");
405 	return (rv);
406 }
407 
408 static __inline void
409 wbinvd(void)
410 {
411 	__asm __volatile("wbinvd");
412 }
413 
414 static __inline void
415 write_rflags(u_long rf)
416 {
417 	__asm __volatile("pushq %0;  popfq" : : "r" (rf));
418 }
419 
420 static __inline void
421 wrmsr(u_int msr, uint64_t newval)
422 {
423 	uint32_t low, high;
424 
425 	low = newval;
426 	high = newval >> 32;
427 	__asm __volatile("wrmsr" : : "a" (low), "d" (high), "c" (msr));
428 }
429 
430 static __inline void
431 load_cr0(u_long data)
432 {
433 
434 	__asm __volatile("movq %0,%%cr0" : : "r" (data));
435 }
436 
437 static __inline u_long
438 rcr0(void)
439 {
440 	u_long	data;
441 
442 	__asm __volatile("movq %%cr0,%0" : "=r" (data));
443 	return (data);
444 }
445 
446 static __inline u_long
447 rcr2(void)
448 {
449 	u_long	data;
450 
451 	__asm __volatile("movq %%cr2,%0" : "=r" (data));
452 	return (data);
453 }
454 
455 static __inline void
456 load_cr3(u_long data)
457 {
458 
459 	__asm __volatile("movq %0,%%cr3" : : "r" (data) : "memory");
460 }
461 
462 static __inline u_long
463 rcr3(void)
464 {
465 	u_long	data;
466 
467 	__asm __volatile("movq %%cr3,%0" : "=r" (data));
468 	return (data);
469 }
470 
471 static __inline void
472 load_cr4(u_long data)
473 {
474 	__asm __volatile("movq %0,%%cr4" : : "r" (data));
475 }
476 
477 static __inline u_long
478 rcr4(void)
479 {
480 	u_long	data;
481 
482 	__asm __volatile("movq %%cr4,%0" : "=r" (data));
483 	return (data);
484 }
485 
486 static __inline u_long
487 rxcr(u_int reg)
488 {
489 	u_int low, high;
490 
491 	__asm __volatile("xgetbv" : "=a" (low), "=d" (high) : "c" (reg));
492 	return (low | ((uint64_t)high << 32));
493 }
494 
495 static __inline void
496 load_xcr(u_int reg, u_long val)
497 {
498 	u_int low, high;
499 
500 	low = val;
501 	high = val >> 32;
502 	__asm __volatile("xsetbv" : : "c" (reg), "a" (low), "d" (high));
503 }
504 
505 /*
506  * Global TLB flush (except for thise for pages marked PG_G)
507  */
508 static __inline void
509 invltlb(void)
510 {
511 
512 	load_cr3(rcr3());
513 }
514 
515 #ifndef CR4_PGE
516 #define	CR4_PGE	0x00000080	/* Page global enable */
517 #endif
518 
519 /*
520  * Perform the guaranteed invalidation of all TLB entries.  This
521  * includes the global entries, and entries in all PCIDs, not only the
522  * current context.  The function works both on non-PCID CPUs and CPUs
523  * with the PCID turned off or on.  See IA-32 SDM Vol. 3a 4.10.4.1
524  * Operations that Invalidate TLBs and Paging-Structure Caches.
525  */
526 static __inline void
527 invltlb_glob(void)
528 {
529 	uint64_t cr4;
530 
531 	cr4 = rcr4();
532 	load_cr4(cr4 & ~CR4_PGE);
533 	/*
534 	 * Although preemption at this point could be detrimental to
535 	 * performance, it would not lead to an error.  PG_G is simply
536 	 * ignored if CR4.PGE is clear.  Moreover, in case this block
537 	 * is re-entered, the load_cr4() either above or below will
538 	 * modify CR4.PGE flushing the TLB.
539 	 */
540 	load_cr4(cr4 | CR4_PGE);
541 }
542 
543 /*
544  * TLB flush for an individual page (even if it has PG_G).
545  * Only works on 486+ CPUs (i386 does not have PG_G).
546  */
547 static __inline void
548 invlpg(u_long addr)
549 {
550 
551 	__asm __volatile("invlpg %0" : : "m" (*(char *)addr) : "memory");
552 }
553 
554 #define	INVPCID_ADDR	0
555 #define	INVPCID_CTX	1
556 #define	INVPCID_CTXGLOB	2
557 #define	INVPCID_ALLCTX	3
558 
559 struct invpcid_descr {
560 	uint64_t	pcid:12 __packed;
561 	uint64_t	pad:52 __packed;
562 	uint64_t	addr;
563 } __packed;
564 
565 static __inline void
566 invpcid(struct invpcid_descr *d, int type)
567 {
568 
569 	__asm __volatile("invpcid (%0),%1"
570 	    : : "r" (d), "r" ((u_long)type) : "memory");
571 }
572 
573 static __inline u_short
574 rfs(void)
575 {
576 	u_short sel;
577 	__asm __volatile("movw %%fs,%0" : "=rm" (sel));
578 	return (sel);
579 }
580 
581 static __inline u_short
582 rgs(void)
583 {
584 	u_short sel;
585 	__asm __volatile("movw %%gs,%0" : "=rm" (sel));
586 	return (sel);
587 }
588 
589 static __inline u_short
590 rss(void)
591 {
592 	u_short sel;
593 	__asm __volatile("movw %%ss,%0" : "=rm" (sel));
594 	return (sel);
595 }
596 
597 static __inline void
598 load_ds(u_short sel)
599 {
600 	__asm __volatile("movw %0,%%ds" : : "rm" (sel));
601 }
602 
603 static __inline void
604 load_es(u_short sel)
605 {
606 	__asm __volatile("movw %0,%%es" : : "rm" (sel));
607 }
608 
609 static __inline void
610 cpu_monitor(const void *addr, u_long extensions, u_int hints)
611 {
612 
613 	__asm __volatile("monitor"
614 	    : : "a" (addr), "c" (extensions), "d" (hints));
615 }
616 
617 static __inline void
618 cpu_mwait(u_long extensions, u_int hints)
619 {
620 
621 	__asm __volatile("mwait" : : "a" (hints), "c" (extensions));
622 }
623 
624 static __inline uint32_t
625 rdpkru(void)
626 {
627 	uint32_t res;
628 
629 	__asm __volatile("rdpkru" :  "=a" (res) : "c" (0) : "edx");
630 	return (res);
631 }
632 
633 static __inline void
634 wrpkru(uint32_t mask)
635 {
636 
637 	__asm __volatile("wrpkru" :  : "a" (mask),  "c" (0), "d" (0));
638 }
639 
640 #ifdef _KERNEL
641 /* This is defined in <machine/specialreg.h> but is too painful to get to */
642 #ifndef	MSR_FSBASE
643 #define	MSR_FSBASE	0xc0000100
644 #endif
645 static __inline void
646 load_fs(u_short sel)
647 {
648 	/* Preserve the fsbase value across the selector load */
649 	__asm __volatile("rdmsr; movw %0,%%fs; wrmsr"
650 	    : : "rm" (sel), "c" (MSR_FSBASE) : "eax", "edx");
651 }
652 
653 #ifndef	MSR_GSBASE
654 #define	MSR_GSBASE	0xc0000101
655 #endif
656 static __inline void
657 load_gs(u_short sel)
658 {
659 	/*
660 	 * Preserve the gsbase value across the selector load.
661 	 * Note that we have to disable interrupts because the gsbase
662 	 * being trashed happens to be the kernel gsbase at the time.
663 	 */
664 	__asm __volatile("pushfq; cli; rdmsr; movw %0,%%gs; wrmsr; popfq"
665 	    : : "rm" (sel), "c" (MSR_GSBASE) : "eax", "edx");
666 }
667 #else
668 /* Usable by userland */
669 static __inline void
670 load_fs(u_short sel)
671 {
672 	__asm __volatile("movw %0,%%fs" : : "rm" (sel));
673 }
674 
675 static __inline void
676 load_gs(u_short sel)
677 {
678 	__asm __volatile("movw %0,%%gs" : : "rm" (sel));
679 }
680 #endif
681 
682 static __inline uint64_t
683 rdfsbase(void)
684 {
685 	uint64_t x;
686 
687 	__asm __volatile("rdfsbase %0" : "=r" (x));
688 	return (x);
689 }
690 
691 static __inline void
692 wrfsbase(uint64_t x)
693 {
694 
695 	__asm __volatile("wrfsbase %0" : : "r" (x));
696 }
697 
698 static __inline uint64_t
699 rdgsbase(void)
700 {
701 	uint64_t x;
702 
703 	__asm __volatile("rdgsbase %0" : "=r" (x));
704 	return (x);
705 }
706 
707 static __inline void
708 wrgsbase(uint64_t x)
709 {
710 
711 	__asm __volatile("wrgsbase %0" : : "r" (x));
712 }
713 
714 static __inline void
715 bare_lgdt(struct region_descriptor *addr)
716 {
717 	__asm __volatile("lgdt (%0)" : : "r" (addr));
718 }
719 
720 static __inline void
721 sgdt(struct region_descriptor *addr)
722 {
723 	char *loc;
724 
725 	loc = (char *)addr;
726 	__asm __volatile("sgdt %0" : "=m" (*loc) : : "memory");
727 }
728 
729 static __inline void
730 lidt(struct region_descriptor *addr)
731 {
732 	__asm __volatile("lidt (%0)" : : "r" (addr));
733 }
734 
735 static __inline void
736 sidt(struct region_descriptor *addr)
737 {
738 	char *loc;
739 
740 	loc = (char *)addr;
741 	__asm __volatile("sidt %0" : "=m" (*loc) : : "memory");
742 }
743 
744 static __inline void
745 lldt(u_short sel)
746 {
747 	__asm __volatile("lldt %0" : : "r" (sel));
748 }
749 
750 static __inline u_short
751 sldt(void)
752 {
753 	u_short sel;
754 
755 	__asm __volatile("sldt %0" : "=r" (sel));
756 	return (sel);
757 }
758 
759 static __inline void
760 ltr(u_short sel)
761 {
762 	__asm __volatile("ltr %0" : : "r" (sel));
763 }
764 
765 static __inline uint32_t
766 read_tr(void)
767 {
768 	u_short sel;
769 
770 	__asm __volatile("str %0" : "=r" (sel));
771 	return (sel);
772 }
773 
774 static __inline uint64_t
775 rdr0(void)
776 {
777 	uint64_t data;
778 	__asm __volatile("movq %%dr0,%0" : "=r" (data));
779 	return (data);
780 }
781 
782 static __inline void
783 load_dr0(uint64_t dr0)
784 {
785 	__asm __volatile("movq %0,%%dr0" : : "r" (dr0));
786 }
787 
788 static __inline uint64_t
789 rdr1(void)
790 {
791 	uint64_t data;
792 	__asm __volatile("movq %%dr1,%0" : "=r" (data));
793 	return (data);
794 }
795 
796 static __inline void
797 load_dr1(uint64_t dr1)
798 {
799 	__asm __volatile("movq %0,%%dr1" : : "r" (dr1));
800 }
801 
802 static __inline uint64_t
803 rdr2(void)
804 {
805 	uint64_t data;
806 	__asm __volatile("movq %%dr2,%0" : "=r" (data));
807 	return (data);
808 }
809 
810 static __inline void
811 load_dr2(uint64_t dr2)
812 {
813 	__asm __volatile("movq %0,%%dr2" : : "r" (dr2));
814 }
815 
816 static __inline uint64_t
817 rdr3(void)
818 {
819 	uint64_t data;
820 	__asm __volatile("movq %%dr3,%0" : "=r" (data));
821 	return (data);
822 }
823 
824 static __inline void
825 load_dr3(uint64_t dr3)
826 {
827 	__asm __volatile("movq %0,%%dr3" : : "r" (dr3));
828 }
829 
830 static __inline uint64_t
831 rdr6(void)
832 {
833 	uint64_t data;
834 	__asm __volatile("movq %%dr6,%0" : "=r" (data));
835 	return (data);
836 }
837 
838 static __inline void
839 load_dr6(uint64_t dr6)
840 {
841 	__asm __volatile("movq %0,%%dr6" : : "r" (dr6));
842 }
843 
844 static __inline uint64_t
845 rdr7(void)
846 {
847 	uint64_t data;
848 	__asm __volatile("movq %%dr7,%0" : "=r" (data));
849 	return (data);
850 }
851 
852 static __inline void
853 load_dr7(uint64_t dr7)
854 {
855 	__asm __volatile("movq %0,%%dr7" : : "r" (dr7));
856 }
857 
858 static __inline register_t
859 intr_disable(void)
860 {
861 	register_t rflags;
862 
863 	rflags = read_rflags();
864 	disable_intr();
865 	return (rflags);
866 }
867 
868 static __inline void
869 intr_restore(register_t rflags)
870 {
871 	write_rflags(rflags);
872 }
873 
874 static __inline void
875 stac(void)
876 {
877 
878 	__asm __volatile("stac" : : : "cc");
879 }
880 
881 static __inline void
882 clac(void)
883 {
884 
885 	__asm __volatile("clac" : : : "cc");
886 }
887 
888 enum {
889 	SGX_ECREATE	= 0x0,
890 	SGX_EADD	= 0x1,
891 	SGX_EINIT	= 0x2,
892 	SGX_EREMOVE	= 0x3,
893 	SGX_EDGBRD	= 0x4,
894 	SGX_EDGBWR	= 0x5,
895 	SGX_EEXTEND	= 0x6,
896 	SGX_ELDU	= 0x8,
897 	SGX_EBLOCK	= 0x9,
898 	SGX_EPA		= 0xA,
899 	SGX_EWB		= 0xB,
900 	SGX_ETRACK	= 0xC,
901 };
902 
903 enum {
904 	SGX_PT_SECS = 0x00,
905 	SGX_PT_TCS  = 0x01,
906 	SGX_PT_REG  = 0x02,
907 	SGX_PT_VA   = 0x03,
908 	SGX_PT_TRIM = 0x04,
909 };
910 
911 int sgx_encls(uint32_t eax, uint64_t rbx, uint64_t rcx, uint64_t rdx);
912 
913 static __inline int
914 sgx_ecreate(void *pginfo, void *secs)
915 {
916 
917 	return (sgx_encls(SGX_ECREATE, (uint64_t)pginfo,
918 	    (uint64_t)secs, 0));
919 }
920 
921 static __inline int
922 sgx_eadd(void *pginfo, void *epc)
923 {
924 
925 	return (sgx_encls(SGX_EADD, (uint64_t)pginfo,
926 	    (uint64_t)epc, 0));
927 }
928 
929 static __inline int
930 sgx_einit(void *sigstruct, void *secs, void *einittoken)
931 {
932 
933 	return (sgx_encls(SGX_EINIT, (uint64_t)sigstruct,
934 	    (uint64_t)secs, (uint64_t)einittoken));
935 }
936 
937 static __inline int
938 sgx_eextend(void *secs, void *epc)
939 {
940 
941 	return (sgx_encls(SGX_EEXTEND, (uint64_t)secs,
942 	    (uint64_t)epc, 0));
943 }
944 
945 static __inline int
946 sgx_epa(void *epc)
947 {
948 
949 	return (sgx_encls(SGX_EPA, SGX_PT_VA, (uint64_t)epc, 0));
950 }
951 
952 static __inline int
953 sgx_eldu(uint64_t rbx, uint64_t rcx,
954     uint64_t rdx)
955 {
956 
957 	return (sgx_encls(SGX_ELDU, rbx, rcx, rdx));
958 }
959 
960 static __inline int
961 sgx_eremove(void *epc)
962 {
963 
964 	return (sgx_encls(SGX_EREMOVE, 0, (uint64_t)epc, 0));
965 }
966 
967 #else /* !(__GNUCLIKE_ASM && __CC_SUPPORTS___INLINE) */
968 
969 int	breakpoint(void);
970 u_int	bsfl(u_int mask);
971 u_int	bsrl(u_int mask);
972 void	clflush(u_long addr);
973 void	clts(void);
974 void	cpuid_count(u_int ax, u_int cx, u_int *p);
975 void	disable_intr(void);
976 void	do_cpuid(u_int ax, u_int *p);
977 void	enable_intr(void);
978 void	halt(void);
979 void	ia32_pause(void);
980 u_char	inb(u_int port);
981 u_int	inl(u_int port);
982 void	insb(u_int port, void *addr, size_t count);
983 void	insl(u_int port, void *addr, size_t count);
984 void	insw(u_int port, void *addr, size_t count);
985 register_t	intr_disable(void);
986 void	intr_restore(register_t rf);
987 void	invd(void);
988 void	invlpg(u_int addr);
989 void	invltlb(void);
990 u_short	inw(u_int port);
991 void	lidt(struct region_descriptor *addr);
992 void	lldt(u_short sel);
993 void	load_cr0(u_long cr0);
994 void	load_cr3(u_long cr3);
995 void	load_cr4(u_long cr4);
996 void	load_dr0(uint64_t dr0);
997 void	load_dr1(uint64_t dr1);
998 void	load_dr2(uint64_t dr2);
999 void	load_dr3(uint64_t dr3);
1000 void	load_dr6(uint64_t dr6);
1001 void	load_dr7(uint64_t dr7);
1002 void	load_fs(u_short sel);
1003 void	load_gs(u_short sel);
1004 void	ltr(u_short sel);
1005 void	outb(u_int port, u_char data);
1006 void	outl(u_int port, u_int data);
1007 void	outsb(u_int port, const void *addr, size_t count);
1008 void	outsl(u_int port, const void *addr, size_t count);
1009 void	outsw(u_int port, const void *addr, size_t count);
1010 void	outw(u_int port, u_short data);
1011 u_long	rcr0(void);
1012 u_long	rcr2(void);
1013 u_long	rcr3(void);
1014 u_long	rcr4(void);
1015 uint64_t rdmsr(u_int msr);
1016 uint32_t rdmsr32(u_int msr);
1017 uint64_t rdpmc(u_int pmc);
1018 uint64_t rdr0(void);
1019 uint64_t rdr1(void);
1020 uint64_t rdr2(void);
1021 uint64_t rdr3(void);
1022 uint64_t rdr6(void);
1023 uint64_t rdr7(void);
1024 uint64_t rdtsc(void);
1025 u_long	read_rflags(void);
1026 u_int	rfs(void);
1027 u_int	rgs(void);
1028 void	wbinvd(void);
1029 void	write_rflags(u_int rf);
1030 void	wrmsr(u_int msr, uint64_t newval);
1031 
1032 #endif	/* __GNUCLIKE_ASM && __CC_SUPPORTS___INLINE */
1033 
1034 void	reset_dbregs(void);
1035 
1036 #ifdef _KERNEL
1037 int	rdmsr_safe(u_int msr, uint64_t *val);
1038 int	wrmsr_safe(u_int msr, uint64_t newval);
1039 #endif
1040 
1041 #endif /* !_MACHINE_CPUFUNC_H_ */
1042