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