2 * Copyright (c) 1993 The Regents of the University of California.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 4. Neither the name of the University nor the names of its contributors
14 * may be used to endorse or promote products derived from this software
15 * without specific prior written permission.
17 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * Functions to provide access to special i386 instructions.
34 * This in included in sys/systm.h, and that file should be
35 * used in preference to this.
38 #ifndef _MACHINE_CPUFUNC_H_
39 #define _MACHINE_CPUFUNC_H_
42 #error this file needs sys/cdefs.h as a prerequisite
45 struct region_descriptor;
47 #define readb(va) (*(volatile u_int8_t *) (va))
48 #define readw(va) (*(volatile u_int16_t *) (va))
49 #define readl(va) (*(volatile u_int32_t *) (va))
51 #define writeb(va, d) (*(volatile u_int8_t *) (va) = (d))
52 #define writew(va, d) (*(volatile u_int16_t *) (va) = (d))
53 #define writel(va, d) (*(volatile u_int32_t *) (va) = (d))
55 #if defined(__GNUCLIKE_ASM) && defined(__CC_SUPPORTS___INLINE)
60 __asm __volatile("int $3");
68 __asm __volatile("bsfl %1,%0" : "=r" (result) : "rm" (mask));
77 __asm __volatile("bsrl %1,%0" : "=r" (result) : "rm" (mask));
84 __asm __volatile("cli" : : : "memory");
88 do_cpuid(u_int ax, u_int *p)
90 __asm __volatile("cpuid"
91 : "=a" (p[0]), "=b" (p[1]), "=c" (p[2]), "=d" (p[3])
96 cpuid_count(u_int ax, u_int cx, u_int *p)
98 __asm __volatile("cpuid"
99 : "=a" (p[0]), "=b" (p[1]), "=c" (p[2]), "=d" (p[3])
100 : "0" (ax), "c" (cx));
106 __asm __volatile("sti");
111 #define HAVE_INLINE_FFS
117 * Note that gcc-2's builtin ffs would be used if we didn't declare
118 * this inline or turn off the builtin. The builtin is faster but
119 * broken in gcc-2.4.5 and slower but working in gcc-2.5 and later
122 return (mask == 0 ? mask : (int)bsfl((u_int)mask) + 1);
125 #define HAVE_INLINE_FLS
130 return (mask == 0 ? mask : (int)bsrl((u_int)mask) + 1);
138 __asm __volatile("hlt");
141 #if !defined(__GNUCLIKE_BUILTIN_CONSTANT_P) || __GNUCLIKE_ASM < 3
143 #define inb(port) inbv(port)
144 #define outb(port, data) outbv(port, data)
146 #else /* __GNUCLIKE_BUILTIN_CONSTANT_P && __GNUCLIKE_ASM >= 3 */
149 * The following complications are to get around gcc not having a
150 * constraint letter for the range 0..255. We still put "d" in the
151 * constraint because "i" isn't a valid constraint when the port
152 * isn't constant. This only matters for -O0 because otherwise
153 * the non-working version gets optimized away.
155 * Use an expression-statement instead of a conditional expression
156 * because gcc-2.6.0 would promote the operands of the conditional
157 * and produce poor code for "if ((inb(var) & const1) == const2)".
159 * The unnecessary test `(port) < 0x10000' is to generate a warning if
160 * the `port' has type u_short or smaller. Such types are pessimal.
161 * This actually only works for signed types. The range check is
162 * careful to avoid generating warnings.
164 #define inb(port) __extension__ ({ \
166 if (__builtin_constant_p(port) && ((port) & 0xffff) < 0x100 \
167 && (port) < 0x10000) \
168 _data = inbc(port); \
170 _data = inbv(port); \
173 #define outb(port, data) ( \
174 __builtin_constant_p(port) && ((port) & 0xffff) < 0x100 \
175 && (port) < 0x10000 \
176 ? outbc(port, data) : outbv(port, data))
178 static __inline u_char
183 __asm __volatile("inb %1,%0" : "=a" (data) : "id" ((u_short)(port)));
188 outbc(u_int port, u_char data)
190 __asm __volatile("outb %0,%1" : : "a" (data), "id" ((u_short)(port)));
193 #endif /* __GNUCLIKE_BUILTIN_CONSTANT_P && __GNUCLIKE_ASM >= 3*/
195 static __inline u_char
200 * We use %%dx and not %1 here because i/o is done at %dx and not at
201 * %edx, while gcc generates inferior code (movw instead of movl)
202 * if we tell it to load (u_short) port.
204 __asm __volatile("inb %%dx,%0" : "=a" (data) : "d" (port));
208 static __inline u_int
213 __asm __volatile("inl %%dx,%0" : "=a" (data) : "d" (port));
218 insb(u_int port, void *addr, size_t cnt)
220 __asm __volatile("cld; rep; insb"
221 : "+D" (addr), "+c" (cnt)
227 insw(u_int port, void *addr, size_t cnt)
229 __asm __volatile("cld; rep; insw"
230 : "+D" (addr), "+c" (cnt)
236 insl(u_int port, void *addr, size_t cnt)
238 __asm __volatile("cld; rep; insl"
239 : "+D" (addr), "+c" (cnt)
247 __asm __volatile("invd");
250 static __inline u_short
255 __asm __volatile("inw %%dx,%0" : "=a" (data) : "d" (port));
260 outbv(u_int port, u_char data)
264 * Use an unnecessary assignment to help gcc's register allocator.
265 * This make a large difference for gcc-1.40 and a tiny difference
266 * for gcc-2.6.0. For gcc-1.40, al had to be ``asm("ax")'' for
267 * best results. gcc-2.6.0 can't handle this.
270 __asm __volatile("outb %0,%%dx" : : "a" (al), "d" (port));
274 outl(u_int port, u_int data)
277 * outl() and outw() aren't used much so we haven't looked at
278 * possible micro-optimizations such as the unnecessary
279 * assignment for them.
281 __asm __volatile("outl %0,%%dx" : : "a" (data), "d" (port));
285 outsb(u_int port, const void *addr, size_t cnt)
287 __asm __volatile("cld; rep; outsb"
288 : "+S" (addr), "+c" (cnt)
293 outsw(u_int port, const void *addr, size_t cnt)
295 __asm __volatile("cld; rep; outsw"
296 : "+S" (addr), "+c" (cnt)
301 outsl(u_int port, const void *addr, size_t cnt)
303 __asm __volatile("cld; rep; outsl"
304 : "+S" (addr), "+c" (cnt)
309 outw(u_int port, u_short data)
311 __asm __volatile("outw %0,%%dx" : : "a" (data), "d" (port));
317 __asm __volatile("pause");
320 static __inline u_int
325 __asm __volatile("pushfl; popl %0" : "=r" (ef));
329 static __inline uint64_t
334 __asm __volatile("rdmsr" : "=A" (rv) : "c" (msr));
338 static __inline uint64_t
343 __asm __volatile("rdpmc" : "=A" (rv) : "c" (pmc));
347 static __inline uint64_t
352 __asm __volatile("rdtsc" : "=A" (rv));
359 __asm __volatile("wbinvd");
363 write_eflags(u_int ef)
365 __asm __volatile("pushl %0; popfl" : : "r" (ef));
369 wrmsr(u_int msr, uint64_t newval)
371 __asm __volatile("wrmsr" : : "A" (newval), "c" (msr));
378 __asm __volatile("movl %0,%%cr0" : : "r" (data));
381 static __inline u_int
386 __asm __volatile("movl %%cr0,%0" : "=r" (data));
390 static __inline u_int
395 __asm __volatile("movl %%cr2,%0" : "=r" (data));
403 __asm __volatile("movl %0,%%cr3" : : "r" (data) : "memory");
406 static __inline u_int
411 __asm __volatile("movl %%cr3,%0" : "=r" (data));
418 __asm __volatile("movl %0,%%cr4" : : "r" (data));
421 static __inline u_int
426 __asm __volatile("movl %%cr4,%0" : "=r" (data));
431 * Global TLB flush (except for thise for pages marked PG_G)
441 * TLB flush for an individual page (even if it has PG_G).
442 * Only works on 486+ CPUs (i386 does not have PG_G).
448 __asm __volatile("invlpg %0" : : "m" (*(char *)addr) : "memory");
451 static __inline u_int
455 __asm __volatile("movl %%fs,%0" : "=rm" (sel));
459 static __inline uint64_t
463 __asm __volatile("sgdt %0" : "=m" (gdtr));
467 static __inline u_int
471 __asm __volatile("movl %%gs,%0" : "=rm" (sel));
475 static __inline uint64_t
479 __asm __volatile("sidt %0" : "=m" (idtr));
483 static __inline u_short
487 __asm __volatile("sldt %0" : "=g" (ldtr));
491 static __inline u_int
495 __asm __volatile("movl %%ss,%0" : "=rm" (sel));
499 static __inline u_short
503 __asm __volatile("str %0" : "=g" (tr));
510 __asm __volatile("movl %0,%%fs" : : "rm" (sel));
516 __asm __volatile("movl %0,%%gs" : : "rm" (sel));
520 lidt(struct region_descriptor *addr)
522 __asm __volatile("lidt (%0)" : : "r" (addr));
528 __asm __volatile("lldt %0" : : "r" (sel));
534 __asm __volatile("ltr %0" : : "r" (sel));
537 static __inline u_int
541 __asm __volatile("movl %%dr0,%0" : "=r" (data));
548 __asm __volatile("movl %0,%%dr0" : : "r" (dr0));
551 static __inline u_int
555 __asm __volatile("movl %%dr1,%0" : "=r" (data));
562 __asm __volatile("movl %0,%%dr1" : : "r" (dr1));
565 static __inline u_int
569 __asm __volatile("movl %%dr2,%0" : "=r" (data));
576 __asm __volatile("movl %0,%%dr2" : : "r" (dr2));
579 static __inline u_int
583 __asm __volatile("movl %%dr3,%0" : "=r" (data));
590 __asm __volatile("movl %0,%%dr3" : : "r" (dr3));
593 static __inline u_int
597 __asm __volatile("movl %%dr4,%0" : "=r" (data));
604 __asm __volatile("movl %0,%%dr4" : : "r" (dr4));
607 static __inline u_int
611 __asm __volatile("movl %%dr5,%0" : "=r" (data));
618 __asm __volatile("movl %0,%%dr5" : : "r" (dr5));
621 static __inline u_int
625 __asm __volatile("movl %%dr6,%0" : "=r" (data));
632 __asm __volatile("movl %0,%%dr6" : : "r" (dr6));
635 static __inline u_int
639 __asm __volatile("movl %%dr7,%0" : "=r" (data));
646 __asm __volatile("movl %0,%%dr7" : : "r" (dr7));
649 static __inline register_t
654 eflags = read_eflags();
660 intr_restore(register_t eflags)
662 write_eflags(eflags);
665 #else /* !(__GNUCLIKE_ASM && __CC_SUPPORTS___INLINE) */
667 int breakpoint(void);
668 u_int bsfl(u_int mask);
669 u_int bsrl(u_int mask);
670 void disable_intr(void);
671 void do_cpuid(u_int ax, u_int *p);
672 void enable_intr(void);
674 void ia32_pause(void);
675 u_char inb(u_int port);
676 u_int inl(u_int port);
677 void insb(u_int port, void *addr, size_t cnt);
678 void insl(u_int port, void *addr, size_t cnt);
679 void insw(u_int port, void *addr, size_t cnt);
680 register_t intr_disable(void);
681 void intr_restore(register_t ef);
683 void invlpg(u_int addr);
685 u_short inw(u_int port);
686 void lidt(struct region_descriptor *addr);
687 void lldt(u_short sel);
688 void load_cr0(u_int cr0);
689 void load_cr3(u_int cr3);
690 void load_cr4(u_int cr4);
691 void load_dr0(u_int dr0);
692 void load_dr1(u_int dr1);
693 void load_dr2(u_int dr2);
694 void load_dr3(u_int dr3);
695 void load_dr4(u_int dr4);
696 void load_dr5(u_int dr5);
697 void load_dr6(u_int dr6);
698 void load_dr7(u_int dr7);
699 void load_fs(u_int sel);
700 void load_gs(u_int sel);
701 void ltr(u_short sel);
702 void outb(u_int port, u_char data);
703 void outl(u_int port, u_int data);
704 void outsb(u_int port, const void *addr, size_t cnt);
705 void outsl(u_int port, const void *addr, size_t cnt);
706 void outsw(u_int port, const void *addr, size_t cnt);
707 void outw(u_int port, u_short data);
712 uint64_t rdmsr(u_int msr);
713 uint64_t rdpmc(u_int pmc);
722 uint64_t rdtsc(void);
723 u_int read_eflags(void);
731 void write_eflags(u_int ef);
732 void wrmsr(u_int msr, uint64_t newval);
734 #endif /* __GNUCLIKE_ASM && __CC_SUPPORTS___INLINE */
736 void reset_dbregs(void);
739 int rdmsr_safe(u_int msr, uint64_t *val);
740 int wrmsr_safe(u_int msr, uint64_t newval);
743 #endif /* !_MACHINE_CPUFUNC_H_ */