13c4dd356SDavid Greenman /*- 2fcfe57d6SPeter Wemm * Copyright (c) 2003 Peter Wemm. 33c4dd356SDavid Greenman * Copyright (c) 1993 The Regents of the University of California. 43c4dd356SDavid Greenman * All rights reserved. 53c4dd356SDavid Greenman * 63c4dd356SDavid Greenman * Redistribution and use in source and binary forms, with or without 73c4dd356SDavid Greenman * modification, are permitted provided that the following conditions 83c4dd356SDavid Greenman * are met: 93c4dd356SDavid Greenman * 1. Redistributions of source code must retain the above copyright 103c4dd356SDavid Greenman * notice, this list of conditions and the following disclaimer. 113c4dd356SDavid Greenman * 2. Redistributions in binary form must reproduce the above copyright 123c4dd356SDavid Greenman * notice, this list of conditions and the following disclaimer in the 133c4dd356SDavid Greenman * documentation and/or other materials provided with the distribution. 143c4dd356SDavid Greenman * 4. Neither the name of the University nor the names of its contributors 153c4dd356SDavid Greenman * may be used to endorse or promote products derived from this software 163c4dd356SDavid Greenman * without specific prior written permission. 173c4dd356SDavid Greenman * 183c4dd356SDavid Greenman * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 193c4dd356SDavid Greenman * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 203c4dd356SDavid Greenman * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 213c4dd356SDavid Greenman * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 223c4dd356SDavid Greenman * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 233c4dd356SDavid Greenman * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 243c4dd356SDavid Greenman * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 253c4dd356SDavid Greenman * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 263c4dd356SDavid Greenman * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 273c4dd356SDavid Greenman * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 283c4dd356SDavid Greenman * SUCH DAMAGE. 293c4dd356SDavid Greenman * 30c3aac50fSPeter Wemm * $FreeBSD$ 313c4dd356SDavid Greenman */ 323c4dd356SDavid Greenman 335b81b6b3SRodney W. Grimes /* 345b81b6b3SRodney W. Grimes * Functions to provide access to special i386 instructions. 35f5d9a10bSMark Murray * This in included in sys/systm.h, and that file should be 36f5d9a10bSMark Murray * used in preference to this. 375b81b6b3SRodney W. Grimes */ 385b81b6b3SRodney W. Grimes 396e393973SGarrett Wollman #ifndef _MACHINE_CPUFUNC_H_ 40004bedebSBruce Evans #define _MACHINE_CPUFUNC_H_ 416e393973SGarrett Wollman 42a5f50ef9SJoerg Wunsch #ifndef _SYS_CDEFS_H_ 43a5f50ef9SJoerg Wunsch #error this file needs sys/cdefs.h as a prerequisite 44a5f50ef9SJoerg Wunsch #endif 45a5f50ef9SJoerg Wunsch 46eb1443c8SPeter Wemm struct region_descriptor; 47d74ac681SMatthew Dillon 48e31fa854SDoug Rabson #define readb(va) (*(volatile u_int8_t *) (va)) 49e31fa854SDoug Rabson #define readw(va) (*(volatile u_int16_t *) (va)) 50e31fa854SDoug Rabson #define readl(va) (*(volatile u_int32_t *) (va)) 51afa88623SPeter Wemm #define readq(va) (*(volatile u_int64_t *) (va)) 52e31fa854SDoug Rabson 53e31fa854SDoug Rabson #define writeb(va, d) (*(volatile u_int8_t *) (va) = (d)) 54e31fa854SDoug Rabson #define writew(va, d) (*(volatile u_int16_t *) (va) = (d)) 55e31fa854SDoug Rabson #define writel(va, d) (*(volatile u_int32_t *) (va) = (d)) 56afa88623SPeter Wemm #define writeq(va, d) (*(volatile u_int64_t *) (va) = (d)) 57e31fa854SDoug Rabson 58a5f50ef9SJoerg Wunsch #if defined(__GNUCLIKE_ASM) && defined(__CC_SUPPORTS___INLINE) 595b81b6b3SRodney W. Grimes 605dbd168eSBruce Evans static __inline void 615dbd168eSBruce Evans breakpoint(void) 62004bedebSBruce Evans { 63004bedebSBruce Evans __asm __volatile("int $3"); 645b81b6b3SRodney W. Grimes } 655b81b6b3SRodney W. Grimes 66c83b1328SBruce Evans static __inline u_int 67c83b1328SBruce Evans bsfl(u_int mask) 68c83b1328SBruce Evans { 69c83b1328SBruce Evans u_int result; 70c83b1328SBruce Evans 713f9a462fSJohn Baldwin __asm __volatile("bsfl %1,%0" : "=r" (result) : "rm" (mask)); 72c83b1328SBruce Evans return (result); 73c83b1328SBruce Evans } 74c83b1328SBruce Evans 75176ce2b1SPeter Wemm static __inline u_long 76176ce2b1SPeter Wemm bsfq(u_long mask) 77176ce2b1SPeter Wemm { 78176ce2b1SPeter Wemm u_long result; 79176ce2b1SPeter Wemm 80176ce2b1SPeter Wemm __asm __volatile("bsfq %1,%0" : "=r" (result) : "rm" (mask)); 81176ce2b1SPeter Wemm return (result); 82176ce2b1SPeter Wemm } 83176ce2b1SPeter Wemm 84c83b1328SBruce Evans static __inline u_int 85c83b1328SBruce Evans bsrl(u_int mask) 86c83b1328SBruce Evans { 87c83b1328SBruce Evans u_int result; 88c83b1328SBruce Evans 893f9a462fSJohn Baldwin __asm __volatile("bsrl %1,%0" : "=r" (result) : "rm" (mask)); 90c83b1328SBruce Evans return (result); 91c83b1328SBruce Evans } 92c83b1328SBruce Evans 93176ce2b1SPeter Wemm static __inline u_long 94176ce2b1SPeter Wemm bsrq(u_long mask) 95176ce2b1SPeter Wemm { 96176ce2b1SPeter Wemm u_long result; 97176ce2b1SPeter Wemm 98176ce2b1SPeter Wemm __asm __volatile("bsrq %1,%0" : "=r" (result) : "rm" (mask)); 99176ce2b1SPeter Wemm return (result); 100176ce2b1SPeter Wemm } 101176ce2b1SPeter Wemm 102004bedebSBruce Evans static __inline void 1035b81b6b3SRodney W. Grimes disable_intr(void) 1045b81b6b3SRodney W. Grimes { 1058966b85cSJohn Dyson __asm __volatile("cli" : : : "memory"); 1065b81b6b3SRodney W. Grimes } 1075b81b6b3SRodney W. Grimes 108004bedebSBruce Evans static __inline void 109a983fdfeSDavid Malone do_cpuid(u_int ax, u_int *p) 110a983fdfeSDavid Malone { 111a983fdfeSDavid Malone __asm __volatile("cpuid" 112a983fdfeSDavid Malone : "=a" (p[0]), "=b" (p[1]), "=c" (p[2]), "=d" (p[3]) 113a983fdfeSDavid Malone : "0" (ax)); 114a983fdfeSDavid Malone } 115a983fdfeSDavid Malone 116a983fdfeSDavid Malone static __inline void 117f6108b61SJacques Vidrine cpuid_count(u_int ax, u_int cx, u_int *p) 118f6108b61SJacques Vidrine { 119f6108b61SJacques Vidrine __asm __volatile("cpuid" 120f6108b61SJacques Vidrine : "=a" (p[0]), "=b" (p[1]), "=c" (p[2]), "=d" (p[3]) 121f6108b61SJacques Vidrine : "0" (ax), "c" (cx)); 122f6108b61SJacques Vidrine } 123f6108b61SJacques Vidrine 124f6108b61SJacques Vidrine static __inline void 1255b81b6b3SRodney W. Grimes enable_intr(void) 1265b81b6b3SRodney W. Grimes { 127fadc51bdSBruce Evans __asm __volatile("sti"); 1285b81b6b3SRodney W. Grimes } 1295b81b6b3SRodney W. Grimes 130a67ef0a7SBruce Evans #ifdef _KERNEL 131a67ef0a7SBruce Evans 132264c3d87SPeter Wemm #define HAVE_INLINE_FFS 133bc35f5dcSPaul Saab #define ffs(x) __builtin_ffs(x) 134176ce2b1SPeter Wemm 135176ce2b1SPeter Wemm #define HAVE_INLINE_FFSL 136176ce2b1SPeter Wemm 137176ce2b1SPeter Wemm static __inline int 138176ce2b1SPeter Wemm ffsl(long mask) 139176ce2b1SPeter Wemm { 140176ce2b1SPeter Wemm return (mask == 0 ? mask : (int)bsfq((u_long)mask) + 1); 141004bedebSBruce Evans } 142004bedebSBruce Evans 14313f588f8SGarrett Wollman #define HAVE_INLINE_FLS 14413f588f8SGarrett Wollman 14513f588f8SGarrett Wollman static __inline int 14613f588f8SGarrett Wollman fls(int mask) 14713f588f8SGarrett Wollman { 1487e622d3cSMark Murray return (mask == 0 ? mask : (int)bsrl((u_int)mask) + 1); 14913f588f8SGarrett Wollman } 15013f588f8SGarrett Wollman 151176ce2b1SPeter Wemm #define HAVE_INLINE_FLSL 152176ce2b1SPeter Wemm 153176ce2b1SPeter Wemm static __inline int 154176ce2b1SPeter Wemm flsl(long mask) 155176ce2b1SPeter Wemm { 156176ce2b1SPeter Wemm return (mask == 0 ? mask : (int)bsrq((u_long)mask) + 1); 157176ce2b1SPeter Wemm } 158176ce2b1SPeter Wemm 159a67ef0a7SBruce Evans #endif /* _KERNEL */ 160a67ef0a7SBruce Evans 161d7ee4425SMark Murray static __inline void 162d7ee4425SMark Murray halt(void) 163d7ee4425SMark Murray { 164d7ee4425SMark Murray __asm __volatile("hlt"); 165d7ee4425SMark Murray } 166d7ee4425SMark Murray 167a5f50ef9SJoerg Wunsch #if !defined(__GNUCLIKE_BUILTIN_CONSTANT_P) || __GNUCLIKE_ASM < 3 168004bedebSBruce Evans 169004bedebSBruce Evans #define inb(port) inbv(port) 170004bedebSBruce Evans #define outb(port, data) outbv(port, data) 171004bedebSBruce Evans 172a5f50ef9SJoerg Wunsch #else /* __GNUCLIKE_BUILTIN_CONSTANT_P && __GNUCLIKE_ASM >= 3 */ 173004bedebSBruce Evans 174004bedebSBruce Evans /* 1758089a043SBruce Evans * The following complications are to get around gcc not having a 1768089a043SBruce Evans * constraint letter for the range 0..255. We still put "d" in the 1778089a043SBruce Evans * constraint because "i" isn't a valid constraint when the port 1788089a043SBruce Evans * isn't constant. This only matters for -O0 because otherwise 1798089a043SBruce Evans * the non-working version gets optimized away. 1808089a043SBruce Evans * 181004bedebSBruce Evans * Use an expression-statement instead of a conditional expression 182004bedebSBruce Evans * because gcc-2.6.0 would promote the operands of the conditional 183004bedebSBruce Evans * and produce poor code for "if ((inb(var) & const1) == const2)". 184388dfa71SBruce Evans * 185388dfa71SBruce Evans * The unnecessary test `(port) < 0x10000' is to generate a warning if 186388dfa71SBruce Evans * the `port' has type u_short or smaller. Such types are pessimal. 187388dfa71SBruce Evans * This actually only works for signed types. The range check is 188388dfa71SBruce Evans * careful to avoid generating warnings. 189004bedebSBruce Evans */ 190388dfa71SBruce Evans #define inb(port) __extension__ ({ \ 191004bedebSBruce Evans u_char _data; \ 192388dfa71SBruce Evans if (__builtin_constant_p(port) && ((port) & 0xffff) < 0x100 \ 193388dfa71SBruce Evans && (port) < 0x10000) \ 194004bedebSBruce Evans _data = inbc(port); \ 195004bedebSBruce Evans else \ 196004bedebSBruce Evans _data = inbv(port); \ 197004bedebSBruce Evans _data; }) 198004bedebSBruce Evans 199388dfa71SBruce Evans #define outb(port, data) ( \ 200388dfa71SBruce Evans __builtin_constant_p(port) && ((port) & 0xffff) < 0x100 \ 201388dfa71SBruce Evans && (port) < 0x10000 \ 202004bedebSBruce Evans ? outbc(port, data) : outbv(port, data)) 203004bedebSBruce Evans 204004bedebSBruce Evans static __inline u_char 205004bedebSBruce Evans inbc(u_int port) 206004bedebSBruce Evans { 207004bedebSBruce Evans u_char data; 208004bedebSBruce Evans 2098089a043SBruce Evans __asm __volatile("inb %1,%0" : "=a" (data) : "id" ((u_short)(port))); 210004bedebSBruce Evans return (data); 211004bedebSBruce Evans } 212004bedebSBruce Evans 213004bedebSBruce Evans static __inline void 214004bedebSBruce Evans outbc(u_int port, u_char data) 215004bedebSBruce Evans { 2168089a043SBruce Evans __asm __volatile("outb %0,%1" : : "a" (data), "id" ((u_short)(port))); 217004bedebSBruce Evans } 218004bedebSBruce Evans 219cf4e1c46SPeter Wemm #endif /* __GNUCLIKE_BUILTIN_CONSTANT_P && __GNUCLIKE_ASM >= 3*/ 220004bedebSBruce Evans 221004bedebSBruce Evans static __inline u_char 222004bedebSBruce Evans inbv(u_int port) 223004bedebSBruce Evans { 224004bedebSBruce Evans u_char data; 225004bedebSBruce Evans /* 226004bedebSBruce Evans * We use %%dx and not %1 here because i/o is done at %dx and not at 227004bedebSBruce Evans * %edx, while gcc generates inferior code (movw instead of movl) 228004bedebSBruce Evans * if we tell it to load (u_short) port. 229004bedebSBruce Evans */ 230004bedebSBruce Evans __asm __volatile("inb %%dx,%0" : "=a" (data) : "d" (port)); 231004bedebSBruce Evans return (data); 232004bedebSBruce Evans } 233004bedebSBruce Evans 23400be8601SBruce Evans static __inline u_int 235004bedebSBruce Evans inl(u_int port) 236004bedebSBruce Evans { 23700be8601SBruce Evans u_int data; 238004bedebSBruce Evans 239004bedebSBruce Evans __asm __volatile("inl %%dx,%0" : "=a" (data) : "d" (port)); 240004bedebSBruce Evans return (data); 241004bedebSBruce Evans } 242004bedebSBruce Evans 243004bedebSBruce Evans static __inline void 244004bedebSBruce Evans insb(u_int port, void *addr, size_t cnt) 245004bedebSBruce Evans { 246004bedebSBruce Evans __asm __volatile("cld; rep; insb" 2473f9a462fSJohn Baldwin : "+D" (addr), "+c" (cnt) 2483f9a462fSJohn Baldwin : "d" (port) 249896763faSBruce Evans : "memory"); 250004bedebSBruce Evans } 251004bedebSBruce Evans 252004bedebSBruce Evans static __inline void 253004bedebSBruce Evans insw(u_int port, void *addr, size_t cnt) 254004bedebSBruce Evans { 255004bedebSBruce Evans __asm __volatile("cld; rep; insw" 2563f9a462fSJohn Baldwin : "+D" (addr), "+c" (cnt) 2573f9a462fSJohn Baldwin : "d" (port) 258896763faSBruce Evans : "memory"); 259004bedebSBruce Evans } 260004bedebSBruce Evans 261004bedebSBruce Evans static __inline void 262004bedebSBruce Evans insl(u_int port, void *addr, size_t cnt) 263004bedebSBruce Evans { 264004bedebSBruce Evans __asm __volatile("cld; rep; insl" 2653f9a462fSJohn Baldwin : "+D" (addr), "+c" (cnt) 2663f9a462fSJohn Baldwin : "d" (port) 267896763faSBruce Evans : "memory"); 268004bedebSBruce Evans } 269004bedebSBruce Evans 270ece15d78SBruce Evans static __inline void 2714c024bbdSKATO Takenori invd(void) 2724c024bbdSKATO Takenori { 2734c024bbdSKATO Takenori __asm __volatile("invd"); 2744c024bbdSKATO Takenori } 2754c024bbdSKATO Takenori 276004bedebSBruce Evans static __inline u_short 277004bedebSBruce Evans inw(u_int port) 278004bedebSBruce Evans { 279004bedebSBruce Evans u_short data; 280004bedebSBruce Evans 281004bedebSBruce Evans __asm __volatile("inw %%dx,%0" : "=a" (data) : "d" (port)); 282004bedebSBruce Evans return (data); 283004bedebSBruce Evans } 284004bedebSBruce Evans 285004bedebSBruce Evans static __inline void 286004bedebSBruce Evans outbv(u_int port, u_char data) 287004bedebSBruce Evans { 288004bedebSBruce Evans u_char al; 289004bedebSBruce Evans /* 290004bedebSBruce Evans * Use an unnecessary assignment to help gcc's register allocator. 291004bedebSBruce Evans * This make a large difference for gcc-1.40 and a tiny difference 292004bedebSBruce Evans * for gcc-2.6.0. For gcc-1.40, al had to be ``asm("ax")'' for 293004bedebSBruce Evans * best results. gcc-2.6.0 can't handle this. 294004bedebSBruce Evans */ 295004bedebSBruce Evans al = data; 296004bedebSBruce Evans __asm __volatile("outb %0,%%dx" : : "a" (al), "d" (port)); 297004bedebSBruce Evans } 298004bedebSBruce Evans 299004bedebSBruce Evans static __inline void 30000be8601SBruce Evans outl(u_int port, u_int data) 301004bedebSBruce Evans { 302004bedebSBruce Evans /* 303004bedebSBruce Evans * outl() and outw() aren't used much so we haven't looked at 304004bedebSBruce Evans * possible micro-optimizations such as the unnecessary 305004bedebSBruce Evans * assignment for them. 306004bedebSBruce Evans */ 307004bedebSBruce Evans __asm __volatile("outl %0,%%dx" : : "a" (data), "d" (port)); 308004bedebSBruce Evans } 309004bedebSBruce Evans 310004bedebSBruce Evans static __inline void 311e1a1bba4SJustin T. Gibbs outsb(u_int port, const void *addr, size_t cnt) 312004bedebSBruce Evans { 313004bedebSBruce Evans __asm __volatile("cld; rep; outsb" 3143f9a462fSJohn Baldwin : "+S" (addr), "+c" (cnt) 3153f9a462fSJohn Baldwin : "d" (port)); 316004bedebSBruce Evans } 317004bedebSBruce Evans 318004bedebSBruce Evans static __inline void 319e1a1bba4SJustin T. Gibbs outsw(u_int port, const void *addr, size_t cnt) 320004bedebSBruce Evans { 321004bedebSBruce Evans __asm __volatile("cld; rep; outsw" 3223f9a462fSJohn Baldwin : "+S" (addr), "+c" (cnt) 3233f9a462fSJohn Baldwin : "d" (port)); 324004bedebSBruce Evans } 325004bedebSBruce Evans 326004bedebSBruce Evans static __inline void 327e1a1bba4SJustin T. Gibbs outsl(u_int port, const void *addr, size_t cnt) 328004bedebSBruce Evans { 329004bedebSBruce Evans __asm __volatile("cld; rep; outsl" 3303f9a462fSJohn Baldwin : "+S" (addr), "+c" (cnt) 3313f9a462fSJohn Baldwin : "d" (port)); 332004bedebSBruce Evans } 333004bedebSBruce Evans 334004bedebSBruce Evans static __inline void 335004bedebSBruce Evans outw(u_int port, u_short data) 336004bedebSBruce Evans { 337004bedebSBruce Evans __asm __volatile("outw %0,%%dx" : : "a" (data), "d" (port)); 338004bedebSBruce Evans } 339004bedebSBruce Evans 3402be69f32SJohn Baldwin static __inline void 3416b8c6989SJohn Baldwin ia32_pause(void) 3422be69f32SJohn Baldwin { 3432be69f32SJohn Baldwin __asm __volatile("pause"); 3442be69f32SJohn Baldwin } 3452be69f32SJohn Baldwin 346afa88623SPeter Wemm static __inline u_long 347afa88623SPeter Wemm read_rflags(void) 3485b81b6b3SRodney W. Grimes { 349afa88623SPeter Wemm u_long rf; 350004bedebSBruce Evans 351afa88623SPeter Wemm __asm __volatile("pushfq; popq %0" : "=r" (rf)); 352afa88623SPeter Wemm return (rf); 3535b81b6b3SRodney W. Grimes } 3545b81b6b3SRodney W. Grimes 35500be8601SBruce Evans static __inline u_int64_t 3565dbd168eSBruce Evans rdmsr(u_int msr) 3575dbd168eSBruce Evans { 358afa88623SPeter Wemm u_int32_t low, high; 3595dbd168eSBruce Evans 360afa88623SPeter Wemm __asm __volatile("rdmsr" : "=a" (low), "=d" (high) : "c" (msr)); 361afa88623SPeter Wemm return (low | ((u_int64_t)high << 32)); 3625dbd168eSBruce Evans } 3635dbd168eSBruce Evans 36400be8601SBruce Evans static __inline u_int64_t 3655dbd168eSBruce Evans rdpmc(u_int pmc) 3665dbd168eSBruce Evans { 367afa88623SPeter Wemm u_int32_t low, high; 3685dbd168eSBruce Evans 369afa88623SPeter Wemm __asm __volatile("rdpmc" : "=a" (low), "=d" (high) : "c" (pmc)); 370afa88623SPeter Wemm return (low | ((u_int64_t)high << 32)); 3715dbd168eSBruce Evans } 3725dbd168eSBruce Evans 37300be8601SBruce Evans static __inline u_int64_t 3745dbd168eSBruce Evans rdtsc(void) 3755dbd168eSBruce Evans { 376afa88623SPeter Wemm u_int32_t low, high; 3775dbd168eSBruce Evans 378afa88623SPeter Wemm __asm __volatile("rdtsc" : "=a" (low), "=d" (high)); 379afa88623SPeter Wemm return (low | ((u_int64_t)high << 32)); 3805dbd168eSBruce Evans } 3815dbd168eSBruce Evans 382004bedebSBruce Evans static __inline void 3834c024bbdSKATO Takenori wbinvd(void) 3844c024bbdSKATO Takenori { 3854c024bbdSKATO Takenori __asm __volatile("wbinvd"); 3864c024bbdSKATO Takenori } 3874c024bbdSKATO Takenori 3884c024bbdSKATO Takenori static __inline void 389afa88623SPeter Wemm write_rflags(u_long rf) 3905b81b6b3SRodney W. Grimes { 391afa88623SPeter Wemm __asm __volatile("pushq %0; popfq" : : "r" (rf)); 3925b81b6b3SRodney W. Grimes } 3935b81b6b3SRodney W. Grimes 394d69e8502SGarrett Wollman static __inline void 39500be8601SBruce Evans wrmsr(u_int msr, u_int64_t newval) 396d69e8502SGarrett Wollman { 397afa88623SPeter Wemm u_int32_t low, high; 398afa88623SPeter Wemm 399afa88623SPeter Wemm low = newval; 400afa88623SPeter Wemm high = newval >> 32; 401afa88623SPeter Wemm __asm __volatile("wrmsr" : : "a" (low), "d" (high), "c" (msr)); 402d69e8502SGarrett Wollman } 403d69e8502SGarrett Wollman 404f1b665c8SPeter Wemm static __inline void 405afa88623SPeter Wemm load_cr0(u_long data) 406f1b665c8SPeter Wemm { 407f1b665c8SPeter Wemm 408afa88623SPeter Wemm __asm __volatile("movq %0,%%cr0" : : "r" (data)); 409f1b665c8SPeter Wemm } 410f1b665c8SPeter Wemm 411afa88623SPeter Wemm static __inline u_long 412f1b665c8SPeter Wemm rcr0(void) 413f1b665c8SPeter Wemm { 414afa88623SPeter Wemm u_long data; 415f1b665c8SPeter Wemm 416afa88623SPeter Wemm __asm __volatile("movq %%cr0,%0" : "=r" (data)); 417f1b665c8SPeter Wemm return (data); 418f1b665c8SPeter Wemm } 419f1b665c8SPeter Wemm 420afa88623SPeter Wemm static __inline u_long 421f1b665c8SPeter Wemm rcr2(void) 422f1b665c8SPeter Wemm { 423afa88623SPeter Wemm u_long data; 424f1b665c8SPeter Wemm 425afa88623SPeter Wemm __asm __volatile("movq %%cr2,%0" : "=r" (data)); 426f1b665c8SPeter Wemm return (data); 427f1b665c8SPeter Wemm } 428f1b665c8SPeter Wemm 429f1b665c8SPeter Wemm static __inline void 430afa88623SPeter Wemm load_cr3(u_long data) 431f1b665c8SPeter Wemm { 432f1b665c8SPeter Wemm 433afa88623SPeter Wemm __asm __volatile("movq %0,%%cr3" : : "r" (data) : "memory"); 434f1b665c8SPeter Wemm } 435f1b665c8SPeter Wemm 436afa88623SPeter Wemm static __inline u_long 437f1b665c8SPeter Wemm rcr3(void) 438f1b665c8SPeter Wemm { 439afa88623SPeter Wemm u_long data; 440f1b665c8SPeter Wemm 441afa88623SPeter Wemm __asm __volatile("movq %%cr3,%0" : "=r" (data)); 442f1b665c8SPeter Wemm return (data); 443f1b665c8SPeter Wemm } 444f1b665c8SPeter Wemm 445f1b665c8SPeter Wemm static __inline void 446afa88623SPeter Wemm load_cr4(u_long data) 447f1b665c8SPeter Wemm { 448afa88623SPeter Wemm __asm __volatile("movq %0,%%cr4" : : "r" (data)); 449f1b665c8SPeter Wemm } 450f1b665c8SPeter Wemm 451afa88623SPeter Wemm static __inline u_long 452f1b665c8SPeter Wemm rcr4(void) 453f1b665c8SPeter Wemm { 454afa88623SPeter Wemm u_long data; 455f1b665c8SPeter Wemm 456afa88623SPeter Wemm __asm __volatile("movq %%cr4,%0" : "=r" (data)); 457f1b665c8SPeter Wemm return (data); 458f1b665c8SPeter Wemm } 459f1b665c8SPeter Wemm 460f1b665c8SPeter Wemm /* 461f1b665c8SPeter Wemm * Global TLB flush (except for thise for pages marked PG_G) 462f1b665c8SPeter Wemm */ 463f1b665c8SPeter Wemm static __inline void 464f1b665c8SPeter Wemm invltlb(void) 465f1b665c8SPeter Wemm { 466f1b665c8SPeter Wemm 467f1b665c8SPeter Wemm load_cr3(rcr3()); 468f1b665c8SPeter Wemm } 469f1b665c8SPeter Wemm 470f1b665c8SPeter Wemm /* 471f1b665c8SPeter Wemm * TLB flush for an individual page (even if it has PG_G). 472f1b665c8SPeter Wemm * Only works on 486+ CPUs (i386 does not have PG_G). 473f1b665c8SPeter Wemm */ 474f1b665c8SPeter Wemm static __inline void 475afa88623SPeter Wemm invlpg(u_long addr) 476f1b665c8SPeter Wemm { 477f1b665c8SPeter Wemm 478f1b665c8SPeter Wemm __asm __volatile("invlpg %0" : : "m" (*(char *)addr) : "memory"); 479f1b665c8SPeter Wemm } 480f1b665c8SPeter Wemm 4815206bca1SLuoqi Chen static __inline u_int 4825206bca1SLuoqi Chen rfs(void) 4835206bca1SLuoqi Chen { 484d1fc2022SDavid Xu u_int sel; 485e6493bbeSDavid E. O'Brien __asm __volatile("mov %%fs,%0" : "=rm" (sel)); 4865206bca1SLuoqi Chen return (sel); 4875206bca1SLuoqi Chen } 4885206bca1SLuoqi Chen 4895206bca1SLuoqi Chen static __inline u_int 4905206bca1SLuoqi Chen rgs(void) 4915206bca1SLuoqi Chen { 492d1fc2022SDavid Xu u_int sel; 493e6493bbeSDavid E. O'Brien __asm __volatile("mov %%gs,%0" : "=rm" (sel)); 4945206bca1SLuoqi Chen return (sel); 4955206bca1SLuoqi Chen } 4965206bca1SLuoqi Chen 497cd0149e3SPeter Wemm static __inline u_int 498cd0149e3SPeter Wemm rss(void) 499cd0149e3SPeter Wemm { 500cd0149e3SPeter Wemm u_int sel; 501e6493bbeSDavid E. O'Brien __asm __volatile("mov %%ss,%0" : "=rm" (sel)); 502cd0149e3SPeter Wemm return (sel); 503cd0149e3SPeter Wemm } 504cd0149e3SPeter Wemm 5055206bca1SLuoqi Chen static __inline void 506d85631c4SPeter Wemm load_ds(u_int sel) 507d85631c4SPeter Wemm { 508e6493bbeSDavid E. O'Brien __asm __volatile("mov %0,%%ds" : : "rm" (sel)); 509d85631c4SPeter Wemm } 510d85631c4SPeter Wemm 511d85631c4SPeter Wemm static __inline void 512d85631c4SPeter Wemm load_es(u_int sel) 513d85631c4SPeter Wemm { 514e6493bbeSDavid E. O'Brien __asm __volatile("mov %0,%%es" : : "rm" (sel)); 515d85631c4SPeter Wemm } 516d85631c4SPeter Wemm 51766247efaSJeff Roberson static inline void 51866247efaSJeff Roberson cpu_monitor(const void *addr, int extensions, int hints) 51966247efaSJeff Roberson { 52066247efaSJeff Roberson __asm __volatile("monitor;" 52166247efaSJeff Roberson : :"a" (addr), "c" (extensions), "d"(hints)); 52266247efaSJeff Roberson } 52366247efaSJeff Roberson 52466247efaSJeff Roberson static inline void 52566247efaSJeff Roberson cpu_mwait(int extensions, int hints) 52666247efaSJeff Roberson { 52766247efaSJeff Roberson __asm __volatile("mwait;" : :"a" (hints), "c" (extensions)); 52866247efaSJeff Roberson } 52966247efaSJeff Roberson 530c0a54ff6SPeter Wemm #ifdef _KERNEL 531c0a54ff6SPeter Wemm /* This is defined in <machine/specialreg.h> but is too painful to get to */ 532c0a54ff6SPeter Wemm #ifndef MSR_FSBASE 533c0a54ff6SPeter Wemm #define MSR_FSBASE 0xc0000100 534c0a54ff6SPeter Wemm #endif 535c0a54ff6SPeter Wemm static __inline void 536c0a54ff6SPeter Wemm load_fs(u_int sel) 537c0a54ff6SPeter Wemm { 538c0a54ff6SPeter Wemm /* Preserve the fsbase value across the selector load */ 539e6493bbeSDavid E. O'Brien __asm __volatile("rdmsr; mov %0,%%fs; wrmsr" 540db26a671SEd Schouten : : "rm" (sel), "c" (MSR_FSBASE) : "eax", "edx"); 541c0a54ff6SPeter Wemm } 542c0a54ff6SPeter Wemm 543c0a54ff6SPeter Wemm #ifndef MSR_GSBASE 544c0a54ff6SPeter Wemm #define MSR_GSBASE 0xc0000101 545c0a54ff6SPeter Wemm #endif 546c0a54ff6SPeter Wemm static __inline void 547c0a54ff6SPeter Wemm load_gs(u_int sel) 548c0a54ff6SPeter Wemm { 549c0a54ff6SPeter Wemm /* 550c0a54ff6SPeter Wemm * Preserve the gsbase value across the selector load. 551c0a54ff6SPeter Wemm * Note that we have to disable interrupts because the gsbase 552c0a54ff6SPeter Wemm * being trashed happens to be the kernel gsbase at the time. 553c0a54ff6SPeter Wemm */ 554e6493bbeSDavid E. O'Brien __asm __volatile("pushfq; cli; rdmsr; mov %0,%%gs; wrmsr; popfq" 555db26a671SEd Schouten : : "rm" (sel), "c" (MSR_GSBASE) : "eax", "edx"); 556c0a54ff6SPeter Wemm } 557c0a54ff6SPeter Wemm #else 558c0a54ff6SPeter Wemm /* Usable by userland */ 559d85631c4SPeter Wemm static __inline void 5605206bca1SLuoqi Chen load_fs(u_int sel) 5615206bca1SLuoqi Chen { 562e6493bbeSDavid E. O'Brien __asm __volatile("mov %0,%%fs" : : "rm" (sel)); 5635206bca1SLuoqi Chen } 5645206bca1SLuoqi Chen 5655206bca1SLuoqi Chen static __inline void 5665206bca1SLuoqi Chen load_gs(u_int sel) 5675206bca1SLuoqi Chen { 568e6493bbeSDavid E. O'Brien __asm __volatile("mov %0,%%gs" : : "rm" (sel)); 5695206bca1SLuoqi Chen } 570c0a54ff6SPeter Wemm #endif 5715206bca1SLuoqi Chen 572eb1443c8SPeter Wemm static __inline void 573eb1443c8SPeter Wemm lidt(struct region_descriptor *addr) 574eb1443c8SPeter Wemm { 575eb1443c8SPeter Wemm __asm __volatile("lidt (%0)" : : "r" (addr)); 576eb1443c8SPeter Wemm } 577eb1443c8SPeter Wemm 578eb1443c8SPeter Wemm static __inline void 579eb1443c8SPeter Wemm lldt(u_short sel) 580eb1443c8SPeter Wemm { 581eb1443c8SPeter Wemm __asm __volatile("lldt %0" : : "r" (sel)); 582eb1443c8SPeter Wemm } 583eb1443c8SPeter Wemm 584eb1443c8SPeter Wemm static __inline void 585eb1443c8SPeter Wemm ltr(u_short sel) 586eb1443c8SPeter Wemm { 587eb1443c8SPeter Wemm __asm __volatile("ltr %0" : : "r" (sel)); 588eb1443c8SPeter Wemm } 589eb1443c8SPeter Wemm 5901182b177SPeter Wemm static __inline u_int64_t 5911182b177SPeter Wemm rdr0(void) 5921182b177SPeter Wemm { 5931182b177SPeter Wemm u_int64_t data; 5941182b177SPeter Wemm __asm __volatile("movq %%dr0,%0" : "=r" (data)); 5951182b177SPeter Wemm return (data); 5961182b177SPeter Wemm } 5971182b177SPeter Wemm 5981182b177SPeter Wemm static __inline void 5991182b177SPeter Wemm load_dr0(u_int64_t dr0) 6001182b177SPeter Wemm { 6011182b177SPeter Wemm __asm __volatile("movq %0,%%dr0" : : "r" (dr0)); 6021182b177SPeter Wemm } 6031182b177SPeter Wemm 6041182b177SPeter Wemm static __inline u_int64_t 6051182b177SPeter Wemm rdr1(void) 6061182b177SPeter Wemm { 6071182b177SPeter Wemm u_int64_t data; 6081182b177SPeter Wemm __asm __volatile("movq %%dr1,%0" : "=r" (data)); 6091182b177SPeter Wemm return (data); 6101182b177SPeter Wemm } 6111182b177SPeter Wemm 6121182b177SPeter Wemm static __inline void 6131182b177SPeter Wemm load_dr1(u_int64_t dr1) 6141182b177SPeter Wemm { 6151182b177SPeter Wemm __asm __volatile("movq %0,%%dr1" : : "r" (dr1)); 6161182b177SPeter Wemm } 6171182b177SPeter Wemm 6181182b177SPeter Wemm static __inline u_int64_t 6191182b177SPeter Wemm rdr2(void) 6201182b177SPeter Wemm { 6211182b177SPeter Wemm u_int64_t data; 6221182b177SPeter Wemm __asm __volatile("movq %%dr2,%0" : "=r" (data)); 6231182b177SPeter Wemm return (data); 6241182b177SPeter Wemm } 6251182b177SPeter Wemm 6261182b177SPeter Wemm static __inline void 6271182b177SPeter Wemm load_dr2(u_int64_t dr2) 6281182b177SPeter Wemm { 6291182b177SPeter Wemm __asm __volatile("movq %0,%%dr2" : : "r" (dr2)); 6301182b177SPeter Wemm } 6311182b177SPeter Wemm 6321182b177SPeter Wemm static __inline u_int64_t 6331182b177SPeter Wemm rdr3(void) 6341182b177SPeter Wemm { 6351182b177SPeter Wemm u_int64_t data; 6361182b177SPeter Wemm __asm __volatile("movq %%dr3,%0" : "=r" (data)); 6371182b177SPeter Wemm return (data); 6381182b177SPeter Wemm } 6391182b177SPeter Wemm 6401182b177SPeter Wemm static __inline void 6411182b177SPeter Wemm load_dr3(u_int64_t dr3) 6421182b177SPeter Wemm { 6431182b177SPeter Wemm __asm __volatile("movq %0,%%dr3" : : "r" (dr3)); 6441182b177SPeter Wemm } 6451182b177SPeter Wemm 6461182b177SPeter Wemm static __inline u_int64_t 6471182b177SPeter Wemm rdr4(void) 6481182b177SPeter Wemm { 6491182b177SPeter Wemm u_int64_t data; 6501182b177SPeter Wemm __asm __volatile("movq %%dr4,%0" : "=r" (data)); 6511182b177SPeter Wemm return (data); 6521182b177SPeter Wemm } 6531182b177SPeter Wemm 6541182b177SPeter Wemm static __inline void 6551182b177SPeter Wemm load_dr4(u_int64_t dr4) 6561182b177SPeter Wemm { 6571182b177SPeter Wemm __asm __volatile("movq %0,%%dr4" : : "r" (dr4)); 6581182b177SPeter Wemm } 6591182b177SPeter Wemm 6601182b177SPeter Wemm static __inline u_int64_t 6611182b177SPeter Wemm rdr5(void) 6621182b177SPeter Wemm { 6631182b177SPeter Wemm u_int64_t data; 6641182b177SPeter Wemm __asm __volatile("movq %%dr5,%0" : "=r" (data)); 6651182b177SPeter Wemm return (data); 6661182b177SPeter Wemm } 6671182b177SPeter Wemm 6681182b177SPeter Wemm static __inline void 6691182b177SPeter Wemm load_dr5(u_int64_t dr5) 6701182b177SPeter Wemm { 6711182b177SPeter Wemm __asm __volatile("movq %0,%%dr5" : : "r" (dr5)); 6721182b177SPeter Wemm } 6731182b177SPeter Wemm 6741182b177SPeter Wemm static __inline u_int64_t 6751182b177SPeter Wemm rdr6(void) 6761182b177SPeter Wemm { 6771182b177SPeter Wemm u_int64_t data; 6781182b177SPeter Wemm __asm __volatile("movq %%dr6,%0" : "=r" (data)); 6791182b177SPeter Wemm return (data); 6801182b177SPeter Wemm } 6811182b177SPeter Wemm 6821182b177SPeter Wemm static __inline void 6831182b177SPeter Wemm load_dr6(u_int64_t dr6) 6841182b177SPeter Wemm { 6851182b177SPeter Wemm __asm __volatile("movq %0,%%dr6" : : "r" (dr6)); 6861182b177SPeter Wemm } 6871182b177SPeter Wemm 6881182b177SPeter Wemm static __inline u_int64_t 6891182b177SPeter Wemm rdr7(void) 6901182b177SPeter Wemm { 6911182b177SPeter Wemm u_int64_t data; 6921182b177SPeter Wemm __asm __volatile("movq %%dr7,%0" : "=r" (data)); 6931182b177SPeter Wemm return (data); 6941182b177SPeter Wemm } 6951182b177SPeter Wemm 6961182b177SPeter Wemm static __inline void 6971182b177SPeter Wemm load_dr7(u_int64_t dr7) 6981182b177SPeter Wemm { 6991182b177SPeter Wemm __asm __volatile("movq %0,%%dr7" : : "r" (dr7)); 7001182b177SPeter Wemm } 7011182b177SPeter Wemm 702ba74981eSWarner Losh static __inline register_t 703ba74981eSWarner Losh intr_disable(void) 704ba74981eSWarner Losh { 705afa88623SPeter Wemm register_t rflags; 706ba74981eSWarner Losh 707afa88623SPeter Wemm rflags = read_rflags(); 708ba74981eSWarner Losh disable_intr(); 709afa88623SPeter Wemm return (rflags); 710ba74981eSWarner Losh } 711ba74981eSWarner Losh 712ba74981eSWarner Losh static __inline void 713afa88623SPeter Wemm intr_restore(register_t rflags) 714ba74981eSWarner Losh { 715afa88623SPeter Wemm write_rflags(rflags); 716ba74981eSWarner Losh } 717ba74981eSWarner Losh 718a5f50ef9SJoerg Wunsch #else /* !(__GNUCLIKE_ASM && __CC_SUPPORTS___INLINE) */ 7195b81b6b3SRodney W. Grimes 720b63dc6adSAlfred Perlstein int breakpoint(void); 721b63dc6adSAlfred Perlstein u_int bsfl(u_int mask); 722b63dc6adSAlfred Perlstein u_int bsrl(u_int mask); 723b63dc6adSAlfred Perlstein void disable_intr(void); 724b63dc6adSAlfred Perlstein void do_cpuid(u_int ax, u_int *p); 725b63dc6adSAlfred Perlstein void enable_intr(void); 726d7ee4425SMark Murray void halt(void); 7274f6c19e5SPeter Wemm void ia32_pause(void); 728b63dc6adSAlfred Perlstein u_char inb(u_int port); 729b63dc6adSAlfred Perlstein u_int inl(u_int port); 730b63dc6adSAlfred Perlstein void insb(u_int port, void *addr, size_t cnt); 731b63dc6adSAlfred Perlstein void insl(u_int port, void *addr, size_t cnt); 732b63dc6adSAlfred Perlstein void insw(u_int port, void *addr, size_t cnt); 7334f6c19e5SPeter Wemm register_t intr_disable(void); 7344f6c19e5SPeter Wemm void intr_restore(register_t rf); 735b63dc6adSAlfred Perlstein void invd(void); 736b63dc6adSAlfred Perlstein void invlpg(u_int addr); 737b63dc6adSAlfred Perlstein void invltlb(void); 738b63dc6adSAlfred Perlstein u_short inw(u_int port); 739eb1443c8SPeter Wemm void lidt(struct region_descriptor *addr); 740eb1443c8SPeter Wemm void lldt(u_short sel); 7414f6c19e5SPeter Wemm void load_cr0(u_long cr0); 7424f6c19e5SPeter Wemm void load_cr3(u_long cr3); 7434f6c19e5SPeter Wemm void load_cr4(u_long cr4); 7444f6c19e5SPeter Wemm void load_dr0(u_int64_t dr0); 7454f6c19e5SPeter Wemm void load_dr1(u_int64_t dr1); 7464f6c19e5SPeter Wemm void load_dr2(u_int64_t dr2); 7474f6c19e5SPeter Wemm void load_dr3(u_int64_t dr3); 7484f6c19e5SPeter Wemm void load_dr4(u_int64_t dr4); 7494f6c19e5SPeter Wemm void load_dr5(u_int64_t dr5); 7504f6c19e5SPeter Wemm void load_dr6(u_int64_t dr6); 7514f6c19e5SPeter Wemm void load_dr7(u_int64_t dr7); 7524f6c19e5SPeter Wemm void load_fs(u_int sel); 7534f6c19e5SPeter Wemm void load_gs(u_int sel); 754eb1443c8SPeter Wemm void ltr(u_short sel); 755b63dc6adSAlfred Perlstein void outb(u_int port, u_char data); 756b63dc6adSAlfred Perlstein void outl(u_int port, u_int data); 7571bcf24eeSLukas Ertl void outsb(u_int port, const void *addr, size_t cnt); 7581bcf24eeSLukas Ertl void outsl(u_int port, const void *addr, size_t cnt); 7591bcf24eeSLukas Ertl void outsw(u_int port, const void *addr, size_t cnt); 760b63dc6adSAlfred Perlstein void outw(u_int port, u_short data); 7614f6c19e5SPeter Wemm u_long rcr0(void); 7624f6c19e5SPeter Wemm u_long rcr2(void); 7634f6c19e5SPeter Wemm u_long rcr3(void); 7644f6c19e5SPeter Wemm u_long rcr4(void); 765b63dc6adSAlfred Perlstein u_int64_t rdmsr(u_int msr); 766b63dc6adSAlfred Perlstein u_int64_t rdpmc(u_int pmc); 7674f6c19e5SPeter Wemm u_int64_t rdr0(void); 7684f6c19e5SPeter Wemm u_int64_t rdr1(void); 7694f6c19e5SPeter Wemm u_int64_t rdr2(void); 7704f6c19e5SPeter Wemm u_int64_t rdr3(void); 7714f6c19e5SPeter Wemm u_int64_t rdr4(void); 7724f6c19e5SPeter Wemm u_int64_t rdr5(void); 7734f6c19e5SPeter Wemm u_int64_t rdr6(void); 7744f6c19e5SPeter Wemm u_int64_t rdr7(void); 775b63dc6adSAlfred Perlstein u_int64_t rdtsc(void); 776afa88623SPeter Wemm u_int read_rflags(void); 7774f6c19e5SPeter Wemm u_int rfs(void); 7784f6c19e5SPeter Wemm u_int rgs(void); 779b63dc6adSAlfred Perlstein void wbinvd(void); 780afa88623SPeter Wemm void write_rflags(u_int rf); 781b63dc6adSAlfred Perlstein void wrmsr(u_int msr, u_int64_t newval); 782004bedebSBruce Evans 783a5f50ef9SJoerg Wunsch #endif /* __GNUCLIKE_ASM && __CC_SUPPORTS___INLINE */ 7845b81b6b3SRodney W. Grimes 785b63dc6adSAlfred Perlstein void reset_dbregs(void); 786d74ac681SMatthew Dillon 787e085f869SStanislav Sedov #ifdef _KERNEL 788e085f869SStanislav Sedov int rdmsr_safe(u_int msr, uint64_t *val); 789e085f869SStanislav Sedov int wrmsr_safe(u_int msr, uint64_t newval); 790e085f869SStanislav Sedov #endif 791e085f869SStanislav Sedov 792004bedebSBruce Evans #endif /* !_MACHINE_CPUFUNC_H_ */ 793