2 * SPDX-License-Identifier: BSD-3-Clause
4 * Copyright (c) 1993 The Regents of the University of California.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
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.
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
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.
40 #ifndef _MACHINE_CPUFUNC_H_
41 #define _MACHINE_CPUFUNC_H_
44 #error this file needs sys/cdefs.h as a prerequisite
47 struct region_descriptor;
49 #define readb(va) (*(volatile uint8_t *) (va))
50 #define readw(va) (*(volatile uint16_t *) (va))
51 #define readl(va) (*(volatile uint32_t *) (va))
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))
57 #if defined(__GNUCLIKE_ASM) && defined(__CC_SUPPORTS___INLINE)
62 __asm __volatile("int $3");
65 static __inline __pure2 u_int
70 __asm("bsfl %1,%0" : "=r" (result) : "rm" (mask) : "cc");
74 static __inline __pure2 u_int
79 __asm("bsrl %1,%0" : "=r" (result) : "rm" (mask) : "cc");
87 __asm __volatile("clflush %0" : : "m" (*(char *)addr));
91 clflushopt(u_long addr)
94 __asm __volatile(".byte 0x66;clflush %0" : : "m" (*(char *)addr));
101 __asm __volatile("clts");
108 __asm __volatile("cli" : : : "memory");
112 do_cpuid(u_int ax, u_int *p)
114 __asm __volatile("cpuid"
115 : "=a" (p[0]), "=b" (p[1]), "=c" (p[2]), "=d" (p[3])
120 cpuid_count(u_int ax, u_int cx, u_int *p)
122 __asm __volatile("cpuid"
123 : "=a" (p[0]), "=b" (p[1]), "=c" (p[2]), "=d" (p[3])
124 : "0" (ax), "c" (cx));
131 __asm __volatile("sti");
135 cpu_monitor(const void *addr, u_long extensions, u_int hints)
138 __asm __volatile("monitor"
139 : : "a" (addr), "c" (extensions), "d" (hints));
143 cpu_mwait(u_long extensions, u_int hints)
146 __asm __volatile("mwait" : : "a" (hints), "c" (extensions));
153 __asm __volatile("lfence" : : : "memory");
160 __asm __volatile("mfence" : : : "memory");
167 __asm __volatile("sfence" : : : "memory");
172 #define HAVE_INLINE_FFS
174 static __inline __pure2 int
178 * Note that gcc-2's builtin ffs would be used if we didn't declare
179 * this inline or turn off the builtin. The builtin is faster but
180 * broken in gcc-2.4.5 and slower but working in gcc-2.5 and later
183 return (mask == 0 ? mask : (int)bsfl((u_int)mask) + 1);
186 #define HAVE_INLINE_FFSL
188 static __inline __pure2 int
191 return (ffs((int)mask));
194 #define HAVE_INLINE_FLS
196 static __inline __pure2 int
199 return (mask == 0 ? mask : (int)bsrl((u_int)mask) + 1);
202 #define HAVE_INLINE_FLSL
204 static __inline __pure2 int
207 return (fls((int)mask));
215 __asm __volatile("hlt");
218 static __inline u_char
223 __asm __volatile("inb %w1, %0" : "=a" (data) : "Nd" (port));
227 static __inline u_int
232 __asm __volatile("inl %w1, %0" : "=a" (data) : "Nd" (port));
237 insb(u_int port, void *addr, size_t count)
239 __asm __volatile("cld; rep; insb"
240 : "+D" (addr), "+c" (count)
246 insw(u_int port, void *addr, size_t count)
248 __asm __volatile("cld; rep; insw"
249 : "+D" (addr), "+c" (count)
255 insl(u_int port, void *addr, size_t count)
257 __asm __volatile("cld; rep; insl"
258 : "+D" (addr), "+c" (count)
266 __asm __volatile("invd");
269 static __inline u_short
274 __asm __volatile("inw %w1, %0" : "=a" (data) : "Nd" (port));
279 outb(u_int port, u_char data)
281 __asm __volatile("outb %0, %w1" : : "a" (data), "Nd" (port));
285 outl(u_int port, u_int data)
287 __asm __volatile("outl %0, %w1" : : "a" (data), "Nd" (port));
291 outsb(u_int port, const void *addr, size_t count)
293 __asm __volatile("cld; rep; outsb"
294 : "+S" (addr), "+c" (count)
299 outsw(u_int port, const void *addr, size_t count)
301 __asm __volatile("cld; rep; outsw"
302 : "+S" (addr), "+c" (count)
307 outsl(u_int port, const void *addr, size_t count)
309 __asm __volatile("cld; rep; outsl"
310 : "+S" (addr), "+c" (count)
315 outw(u_int port, u_short data)
317 __asm __volatile("outw %0, %w1" : : "a" (data), "Nd" (port));
323 __asm __volatile("pause");
326 static __inline u_int
331 __asm __volatile("pushfl; popl %0" : "=r" (ef));
335 static __inline uint64_t
340 __asm __volatile("rdmsr" : "=A" (rv) : "c" (msr));
344 static __inline uint32_t
349 __asm __volatile("rdmsr" : "=a" (low) : "c" (msr) : "edx");
353 static __inline uint64_t
358 __asm __volatile("rdpmc" : "=A" (rv) : "c" (pmc));
362 static __inline uint64_t
367 __asm __volatile("rdtsc" : "=A" (rv));
371 static __inline uint64_t
376 __asm __volatile("rdtscp" : "=A" (rv) : : "ecx");
380 static __inline uint32_t
385 __asm __volatile("rdtsc" : "=a" (rv) : : "edx");
392 __asm __volatile("wbinvd");
396 write_eflags(u_int ef)
398 __asm __volatile("pushl %0; popfl" : : "r" (ef));
402 wrmsr(u_int msr, uint64_t newval)
404 __asm __volatile("wrmsr" : : "A" (newval), "c" (msr));
411 __asm __volatile("movl %0,%%cr0" : : "r" (data));
414 static __inline u_int
419 __asm __volatile("movl %%cr0,%0" : "=r" (data));
423 static __inline u_int
428 __asm __volatile("movl %%cr2,%0" : "=r" (data));
436 __asm __volatile("movl %0,%%cr3" : : "r" (data) : "memory");
439 static __inline u_int
444 __asm __volatile("movl %%cr3,%0" : "=r" (data));
451 __asm __volatile("movl %0,%%cr4" : : "r" (data));
454 static __inline u_int
459 __asm __volatile("movl %%cr4,%0" : "=r" (data));
463 static __inline uint64_t
468 __asm __volatile("xgetbv" : "=a" (low), "=d" (high) : "c" (reg));
469 return (low | ((uint64_t)high << 32));
473 load_xcr(u_int reg, uint64_t val)
479 __asm __volatile("xsetbv" : : "c" (reg), "a" (low), "d" (high));
483 * Global TLB flush (except for thise for pages marked PG_G)
493 * TLB flush for an individual page (even if it has PG_G).
494 * Only works on 486+ CPUs (i386 does not have PG_G).
500 __asm __volatile("invlpg %0" : : "m" (*(char *)addr) : "memory");
503 static __inline u_short
507 __asm __volatile("movw %%fs,%0" : "=rm" (sel));
511 static __inline uint64_t
515 __asm __volatile("sgdt %0" : "=m" (gdtr));
519 static __inline u_short
523 __asm __volatile("movw %%gs,%0" : "=rm" (sel));
527 static __inline uint64_t
531 __asm __volatile("sidt %0" : "=m" (idtr));
535 static __inline u_short
539 __asm __volatile("sldt %0" : "=g" (ldtr));
543 static __inline u_short
547 __asm __volatile("movw %%ss,%0" : "=rm" (sel));
551 static __inline u_short
555 __asm __volatile("str %0" : "=g" (tr));
562 __asm __volatile("movw %0,%%fs" : : "rm" (sel));
568 __asm __volatile("movw %0,%%gs" : : "rm" (sel));
572 lidt(struct region_descriptor *addr)
574 __asm __volatile("lidt (%0)" : : "r" (addr));
580 __asm __volatile("lldt %0" : : "r" (sel));
586 __asm __volatile("ltr %0" : : "r" (sel));
589 static __inline u_int
593 __asm __volatile("movl %%dr0,%0" : "=r" (data));
600 __asm __volatile("movl %0,%%dr0" : : "r" (dr0));
603 static __inline u_int
607 __asm __volatile("movl %%dr1,%0" : "=r" (data));
614 __asm __volatile("movl %0,%%dr1" : : "r" (dr1));
617 static __inline u_int
621 __asm __volatile("movl %%dr2,%0" : "=r" (data));
628 __asm __volatile("movl %0,%%dr2" : : "r" (dr2));
631 static __inline u_int
635 __asm __volatile("movl %%dr3,%0" : "=r" (data));
642 __asm __volatile("movl %0,%%dr3" : : "r" (dr3));
645 static __inline u_int
649 __asm __volatile("movl %%dr6,%0" : "=r" (data));
656 __asm __volatile("movl %0,%%dr6" : : "r" (dr6));
659 static __inline u_int
663 __asm __volatile("movl %%dr7,%0" : "=r" (data));
670 __asm __volatile("movl %0,%%dr7" : : "r" (dr7));
673 static __inline u_char
674 read_cyrix_reg(u_char reg)
681 write_cyrix_reg(u_char reg, u_char data)
687 static __inline register_t
692 eflags = read_eflags();
698 intr_restore(register_t eflags)
700 write_eflags(eflags);
703 #else /* !(__GNUCLIKE_ASM && __CC_SUPPORTS___INLINE) */
705 int breakpoint(void);
706 u_int bsfl(u_int mask);
707 u_int bsrl(u_int mask);
708 void clflush(u_long addr);
710 void cpuid_count(u_int ax, u_int cx, u_int *p);
711 void disable_intr(void);
712 void do_cpuid(u_int ax, u_int *p);
713 void enable_intr(void);
715 void ia32_pause(void);
716 u_char inb(u_int port);
717 u_int inl(u_int port);
718 void insb(u_int port, void *addr, size_t count);
719 void insl(u_int port, void *addr, size_t count);
720 void insw(u_int port, void *addr, size_t count);
721 register_t intr_disable(void);
722 void intr_restore(register_t ef);
724 void invlpg(u_int addr);
726 u_short inw(u_int port);
727 void lidt(struct region_descriptor *addr);
728 void lldt(u_short sel);
729 void load_cr0(u_int cr0);
730 void load_cr3(u_int cr3);
731 void load_cr4(u_int cr4);
732 void load_dr0(u_int dr0);
733 void load_dr1(u_int dr1);
734 void load_dr2(u_int dr2);
735 void load_dr3(u_int dr3);
736 void load_dr6(u_int dr6);
737 void load_dr7(u_int dr7);
738 void load_fs(u_short sel);
739 void load_gs(u_short sel);
740 void ltr(u_short sel);
741 void outb(u_int port, u_char data);
742 void outl(u_int port, u_int data);
743 void outsb(u_int port, const void *addr, size_t count);
744 void outsl(u_int port, const void *addr, size_t count);
745 void outsw(u_int port, const void *addr, size_t count);
746 void outw(u_int port, u_short data);
751 uint64_t rdmsr(u_int msr);
752 uint64_t rdpmc(u_int pmc);
759 uint64_t rdtsc(void);
760 u_char read_cyrix_reg(u_char reg);
761 u_int read_eflags(void);
769 void write_cyrix_reg(u_char reg, u_char data);
770 void write_eflags(u_int ef);
771 void wrmsr(u_int msr, uint64_t newval);
773 #endif /* __GNUCLIKE_ASM && __CC_SUPPORTS___INLINE */
775 void reset_dbregs(void);
778 int rdmsr_safe(u_int msr, uint64_t *val);
779 int wrmsr_safe(u_int msr, uint64_t newval);
782 #endif /* !_MACHINE_CPUFUNC_H_ */