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
breakpoint(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
clflush(u_long addr)77 clflush(u_long addr)
78 {
79
80 __asm __volatile("clflush %0" : : "m" (*(char *)addr));
81 }
82
83 static __inline void
clflushopt(u_long addr)84 clflushopt(u_long addr)
85 {
86
87 __asm __volatile(".byte 0x66;clflush %0" : : "m" (*(char *)addr));
88 }
89
90 static __inline void
clwb(u_long addr)91 clwb(u_long addr)
92 {
93
94 __asm __volatile("clwb %0" : : "m" (*(char *)addr));
95 }
96
97 static __inline void
clts(void)98 clts(void)
99 {
100
101 __asm __volatile("clts");
102 }
103
104 static __inline void
disable_intr(void)105 disable_intr(void)
106 {
107 __asm __volatile("cli" : : : "memory");
108 }
109
110 static __inline void
do_cpuid(u_int ax,u_int * p)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
cpuid_count(u_int ax,u_int cx,u_int * p)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
enable_intr(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
fls(int mask)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
flsl(long mask)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
flsll(long long mask)162 flsll(long long mask)
163 {
164 return (flsl((long)mask));
165 }
166
167 #endif /* _KERNEL */
168
169 static __inline void
halt(void)170 halt(void)
171 {
172 __asm __volatile("hlt");
173 }
174
175 static __inline u_char
inb(u_int port)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
inl(u_int port)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
insb(u_int port,void * addr,size_t count)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
insw(u_int port,void * addr,size_t count)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
insl(u_int port,void * addr,size_t count)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
invd(void)221 invd(void)
222 {
223 __asm __volatile("invd");
224 }
225
226 static __inline u_short
inw(u_int port)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
outb(u_int port,u_char data)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
outl(u_int port,u_int data)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
outsb(u_int port,const void * addr,size_t count)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
outsw(u_int port,const void * addr,size_t count)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
outsl(u_int port,const void * addr,size_t count)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
outw(u_int port,u_short data)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
popcntq(u_long mask)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
lfence(void)287 lfence(void)
288 {
289
290 __asm __volatile("lfence" : : : "memory");
291 }
292
293 static __inline void
mfence(void)294 mfence(void)
295 {
296
297 __asm __volatile("mfence" : : : "memory");
298 }
299
300 static __inline void
sfence(void)301 sfence(void)
302 {
303
304 __asm __volatile("sfence" : : : "memory");
305 }
306
307 static __inline void
ia32_pause(void)308 ia32_pause(void)
309 {
310 __asm __volatile("pause");
311 }
312
313 static __inline u_long
read_rflags(void)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
rdmsr(u_int msr)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
rdmsr32(u_int msr)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
rdpmc(u_int pmc)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
rdtsc(void)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
rdtsc_ordered_lfence(void)359 rdtsc_ordered_lfence(void)
360 {
361 lfence();
362 return (rdtsc());
363 }
364
365 static __inline uint64_t
rdtsc_ordered_mfence(void)366 rdtsc_ordered_mfence(void)
367 {
368 mfence();
369 return (rdtsc());
370 }
371
372 static __inline uint64_t
rdtscp(void)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
rdtscp_aux(uint32_t * aux)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
rdtsc32(void)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
rdtscp32(void)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
wbinvd(void)409 wbinvd(void)
410 {
411 __asm __volatile("wbinvd");
412 }
413
414 static __inline void
write_rflags(u_long rf)415 write_rflags(u_long rf)
416 {
417 __asm __volatile("pushq %0; popfq" : : "r" (rf));
418 }
419
420 static __inline void
wrmsr(u_int msr,uint64_t newval)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
load_cr0(u_long data)431 load_cr0(u_long data)
432 {
433
434 __asm __volatile("movq %0,%%cr0" : : "r" (data));
435 }
436
437 static __inline u_long
rcr0(void)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
rcr2(void)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
load_cr3(u_long data)456 load_cr3(u_long data)
457 {
458
459 __asm __volatile("movq %0,%%cr3" : : "r" (data) : "memory");
460 }
461
462 static __inline u_long
rcr3(void)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
load_cr4(u_long data)472 load_cr4(u_long data)
473 {
474 __asm __volatile("movq %0,%%cr4" : : "r" (data));
475 }
476
477 static __inline u_long
rcr4(void)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
rxcr(u_int reg)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
load_xcr(u_int reg,u_long val)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
invltlb(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
invltlb_glob(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
invlpg(u_long addr)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
invpcid(struct invpcid_descr * d,int type)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
rfs(void)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
rgs(void)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
rss(void)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
load_ds(u_short sel)598 load_ds(u_short sel)
599 {
600 __asm __volatile("movw %0,%%ds" : : "rm" (sel));
601 }
602
603 static __inline void
load_es(u_short sel)604 load_es(u_short sel)
605 {
606 __asm __volatile("movw %0,%%es" : : "rm" (sel));
607 }
608
609 static __inline void
cpu_monitor(const void * addr,u_long extensions,u_int hints)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
cpu_mwait(u_long extensions,u_int hints)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
rdpkru(void)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
wrpkru(uint32_t mask)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
load_fs(u_short sel)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
load_gs(u_short sel)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
load_fs(u_short sel)670 load_fs(u_short sel)
671 {
672 __asm __volatile("movw %0,%%fs" : : "rm" (sel));
673 }
674
675 static __inline void
load_gs(u_short sel)676 load_gs(u_short sel)
677 {
678 __asm __volatile("movw %0,%%gs" : : "rm" (sel));
679 }
680 #endif
681
682 static __inline uint64_t
rdfsbase(void)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
wrfsbase(uint64_t x)692 wrfsbase(uint64_t x)
693 {
694
695 __asm __volatile("wrfsbase %0" : : "r" (x));
696 }
697
698 static __inline uint64_t
rdgsbase(void)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
wrgsbase(uint64_t x)708 wrgsbase(uint64_t x)
709 {
710
711 __asm __volatile("wrgsbase %0" : : "r" (x));
712 }
713
714 static __inline void
bare_lgdt(struct region_descriptor * addr)715 bare_lgdt(struct region_descriptor *addr)
716 {
717 __asm __volatile("lgdt (%0)" : : "r" (addr));
718 }
719
720 static __inline void
sgdt(struct region_descriptor * addr)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
lidt(struct region_descriptor * addr)730 lidt(struct region_descriptor *addr)
731 {
732 __asm __volatile("lidt (%0)" : : "r" (addr));
733 }
734
735 static __inline void
sidt(struct region_descriptor * addr)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
lldt(u_short sel)745 lldt(u_short sel)
746 {
747 __asm __volatile("lldt %0" : : "r" (sel));
748 }
749
750 static __inline u_short
sldt(void)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
ltr(u_short sel)760 ltr(u_short sel)
761 {
762 __asm __volatile("ltr %0" : : "r" (sel));
763 }
764
765 static __inline uint32_t
read_tr(void)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
rdr0(void)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
load_dr0(uint64_t dr0)783 load_dr0(uint64_t dr0)
784 {
785 __asm __volatile("movq %0,%%dr0" : : "r" (dr0));
786 }
787
788 static __inline uint64_t
rdr1(void)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
load_dr1(uint64_t dr1)797 load_dr1(uint64_t dr1)
798 {
799 __asm __volatile("movq %0,%%dr1" : : "r" (dr1));
800 }
801
802 static __inline uint64_t
rdr2(void)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
load_dr2(uint64_t dr2)811 load_dr2(uint64_t dr2)
812 {
813 __asm __volatile("movq %0,%%dr2" : : "r" (dr2));
814 }
815
816 static __inline uint64_t
rdr3(void)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
load_dr3(uint64_t dr3)825 load_dr3(uint64_t dr3)
826 {
827 __asm __volatile("movq %0,%%dr3" : : "r" (dr3));
828 }
829
830 static __inline uint64_t
rdr6(void)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
load_dr6(uint64_t dr6)839 load_dr6(uint64_t dr6)
840 {
841 __asm __volatile("movq %0,%%dr6" : : "r" (dr6));
842 }
843
844 static __inline uint64_t
rdr7(void)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
load_dr7(uint64_t dr7)853 load_dr7(uint64_t dr7)
854 {
855 __asm __volatile("movq %0,%%dr7" : : "r" (dr7));
856 }
857
858 static __inline register_t
intr_disable(void)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
intr_restore(register_t rflags)869 intr_restore(register_t rflags)
870 {
871 write_rflags(rflags);
872 }
873
874 static __inline void
stac(void)875 stac(void)
876 {
877
878 __asm __volatile("stac" : : : "cc");
879 }
880
881 static __inline void
clac(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
sgx_ecreate(void * pginfo,void * secs)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
sgx_eadd(void * pginfo,void * epc)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
sgx_einit(void * sigstruct,void * secs,void * einittoken)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
sgx_eextend(void * secs,void * epc)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
sgx_epa(void * epc)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
sgx_eldu(uint64_t rbx,uint64_t rcx,uint64_t rdx)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
sgx_eremove(void * epc)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