| Commit | Line | Data |
|---|---|---|
| fc3f9779 SS |
1 | /*- |
| 2 | * Copyright (c) 2003 Peter Wemm. | |
| 3 | * Copyright (c) 1993 The Regents of the University of California. | |
| c8fe38ae | 4 | * Copyright (c) 2008 The DragonFly Project. |
| fc3f9779 SS |
5 | * All rights reserved. |
| 6 | * | |
| 7 | * Redistribution and use in source and binary forms, with or without | |
| 8 | * modification, are permitted provided that the following conditions | |
| 9 | * are met: | |
| 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. All advertising materials mentioning features or use of this software | |
| 16 | * must display the following acknowledgement: | |
| 17 | * This product includes software developed by the University of | |
| 18 | * California, Berkeley and its contributors. | |
| 19 | * 4. Neither the name of the University nor the names of its contributors | |
| 20 | * may be used to endorse or promote products derived from this software | |
| 21 | * without specific prior written permission. | |
| 22 | * | |
| 23 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND | |
| 24 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
| 25 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
| 26 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | |
| 27 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |
| 28 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |
| 29 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
| 30 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
| 31 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |
| 32 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
| 33 | * SUCH DAMAGE. | |
| 34 | * | |
| 35 | * $FreeBSD: src/sys/amd64/include/cpufunc.h,v 1.139 2004/01/28 23:53:04 peter Exp $ | |
| fc3f9779 SS |
36 | */ |
| 37 | ||
| 38 | /* | |
| 39 | * Functions to provide access to special i386 instructions. | |
| 40 | * This in included in sys/systm.h, and that file should be | |
| 41 | * used in preference to this. | |
| 42 | */ | |
| 43 | ||
| 44 | #ifndef _CPU_CPUFUNC_H_ | |
| 45 | #define _CPU_CPUFUNC_H_ | |
| 46 | ||
| 47 | #include <sys/cdefs.h> | |
| 48 | #include <machine/psl.h> | |
| 49 | ||
| 50 | struct thread; | |
| 51 | struct region_descriptor; | |
| 52 | ||
| 53 | __BEGIN_DECLS | |
| 54 | #define readb(va) (*(volatile u_int8_t *) (va)) | |
| 55 | #define readw(va) (*(volatile u_int16_t *) (va)) | |
| 56 | #define readl(va) (*(volatile u_int32_t *) (va)) | |
| 57 | #define readq(va) (*(volatile u_int64_t *) (va)) | |
| 58 | ||
| 59 | #define writeb(va, d) (*(volatile u_int8_t *) (va) = (d)) | |
| 60 | #define writew(va, d) (*(volatile u_int16_t *) (va) = (d)) | |
| 61 | #define writel(va, d) (*(volatile u_int32_t *) (va) = (d)) | |
| 62 | #define writeq(va, d) (*(volatile u_int64_t *) (va) = (d)) | |
| 63 | ||
| 64 | #ifdef __GNUC__ | |
| 65 | ||
| 46d4e165 JG |
66 | #ifdef SMP |
| 67 | #include <machine/lock.h> /* XXX */ | |
| 68 | #endif | |
| 69 | ||
| fc3f9779 SS |
70 | static __inline void |
| 71 | breakpoint(void) | |
| 72 | { | |
| 73 | __asm __volatile("int $3"); | |
| 74 | } | |
| 75 | ||
| d7f50089 YY |
76 | static __inline void |
| 77 | cpu_pause(void) | |
| 78 | { | |
| 79 | __asm __volatile("pause"); | |
| 80 | } | |
| 81 | ||
| fc3f9779 SS |
82 | static __inline u_int |
| 83 | bsfl(u_int mask) | |
| 84 | { | |
| 85 | u_int result; | |
| 86 | ||
| 87 | __asm __volatile("bsfl %1,%0" : "=r" (result) : "rm" (mask)); | |
| 88 | return (result); | |
| 89 | } | |
| 90 | ||
| 91 | static __inline u_long | |
| 92 | bsfq(u_long mask) | |
| 93 | { | |
| 94 | u_long result; | |
| 95 | ||
| 96 | __asm __volatile("bsfq %1,%0" : "=r" (result) : "rm" (mask)); | |
| 97 | return (result); | |
| 98 | } | |
| 99 | ||
| 100 | static __inline u_int | |
| 101 | bsrl(u_int mask) | |
| 102 | { | |
| 103 | u_int result; | |
| 104 | ||
| 105 | __asm __volatile("bsrl %1,%0" : "=r" (result) : "rm" (mask)); | |
| 106 | return (result); | |
| 107 | } | |
| 108 | ||
| 109 | static __inline u_long | |
| 110 | bsrq(u_long mask) | |
| 111 | { | |
| 112 | u_long result; | |
| 113 | ||
| 114 | __asm __volatile("bsrq %1,%0" : "=r" (result) : "rm" (mask)); | |
| 115 | return (result); | |
| 116 | } | |
| 117 | ||
| 118 | static __inline void | |
| c8fe38ae | 119 | cpu_disable_intr(void) |
| fc3f9779 SS |
120 | { |
| 121 | __asm __volatile("cli" : : : "memory"); | |
| 122 | } | |
| 123 | ||
| 124 | static __inline void | |
| 125 | do_cpuid(u_int ax, u_int *p) | |
| 126 | { | |
| 127 | __asm __volatile("cpuid" | |
| 128 | : "=a" (p[0]), "=b" (p[1]), "=c" (p[2]), "=d" (p[3]) | |
| 129 | : "0" (ax)); | |
| 130 | } | |
| 131 | ||
| 132 | static __inline void | |
| c8fe38ae MD |
133 | cpuid_count(u_int ax, u_int cx, u_int *p) |
| 134 | { | |
| 135 | __asm __volatile("cpuid" | |
| 136 | : "=a" (p[0]), "=b" (p[1]), "=c" (p[2]), "=d" (p[3]) | |
| 137 | : "0" (ax), "c" (cx)); | |
| 138 | } | |
| 139 | ||
| 140 | static __inline void | |
| d7f50089 | 141 | cpu_enable_intr(void) |
| fc3f9779 SS |
142 | { |
| 143 | __asm __volatile("sti"); | |
| 144 | } | |
| 145 | ||
| d7f50089 YY |
146 | /* |
| 147 | * Cpu and compiler memory ordering fence. mfence ensures strong read and | |
| 148 | * write ordering. | |
| 149 | * | |
| 150 | * A serializing or fence instruction is required here. A locked bus | |
| 151 | * cycle on data for which we already own cache mastership is the most | |
| 152 | * portable. | |
| 153 | */ | |
| 154 | static __inline void | |
| 155 | cpu_mfence(void) | |
| 156 | { | |
| 157 | #ifdef SMP | |
| 767fc57d | 158 | __asm __volatile("mfence" : : : "memory"); |
| d7f50089 YY |
159 | #else |
| 160 | __asm __volatile("" : : : "memory"); | |
| 161 | #endif | |
| 162 | } | |
| 163 | ||
| 164 | /* | |
| 165 | * cpu_lfence() ensures strong read ordering for reads issued prior | |
| 166 | * to the instruction verses reads issued afterwords. | |
| 167 | * | |
| 168 | * A serializing or fence instruction is required here. A locked bus | |
| 169 | * cycle on data for which we already own cache mastership is the most | |
| 170 | * portable. | |
| 171 | */ | |
| 172 | static __inline void | |
| 173 | cpu_lfence(void) | |
| 174 | { | |
| 175 | #ifdef SMP | |
| 767fc57d | 176 | __asm __volatile("lfence" : : : "memory"); |
| d7f50089 YY |
177 | #else |
| 178 | __asm __volatile("" : : : "memory"); | |
| 179 | #endif | |
| 180 | } | |
| 181 | ||
| 182 | /* | |
| 183 | * cpu_sfence() ensures strong write ordering for writes issued prior | |
| 184 | * to the instruction verses writes issued afterwords. Writes are | |
| 185 | * ordered on intel cpus so we do not actually have to do anything. | |
| 186 | */ | |
| 187 | static __inline void | |
| 188 | cpu_sfence(void) | |
| 189 | { | |
| 767fc57d JG |
190 | #ifdef SMP |
| 191 | __asm __volatile("sfence" : : : "memory"); | |
| 192 | #else | |
| d7f50089 | 193 | __asm __volatile("" : : : "memory"); |
| 767fc57d | 194 | #endif |
| d7f50089 YY |
195 | } |
| 196 | ||
| 197 | /* | |
| 198 | * cpu_ccfence() prevents the compiler from reordering instructions, in | |
| 199 | * particular stores, relative to the current cpu. Use cpu_sfence() if | |
| 200 | * you need to guarentee ordering by both the compiler and by the cpu. | |
| 201 | * | |
| 202 | * This also prevents the compiler from caching memory loads into local | |
| 203 | * variables across the routine. | |
| 204 | */ | |
| 205 | static __inline void | |
| 206 | cpu_ccfence(void) | |
| 207 | { | |
| 208 | __asm __volatile("" : : : "memory"); | |
| 209 | } | |
| 210 | ||
| fc3f9779 SS |
211 | #ifdef _KERNEL |
| 212 | ||
| 213 | #define HAVE_INLINE_FFS | |
| 214 | ||
| 215 | static __inline int | |
| 216 | ffs(int mask) | |
| 217 | { | |
| 218 | #if 0 | |
| 219 | /* | |
| 220 | * Note that gcc-2's builtin ffs would be used if we didn't declare | |
| 221 | * this inline or turn off the builtin. The builtin is faster but | |
| 222 | * broken in gcc-2.4.5 and slower but working in gcc-2.5 and later | |
| 223 | * versions. | |
| 224 | */ | |
| 225 | return (mask == 0 ? mask : (int)bsfl((u_int)mask) + 1); | |
| 226 | #else | |
| 227 | /* Actually, the above is way out of date. The builtins use cmov etc */ | |
| 228 | return (__builtin_ffs(mask)); | |
| 229 | #endif | |
| 230 | } | |
| 231 | ||
| 232 | #define HAVE_INLINE_FFSL | |
| 233 | ||
| 234 | static __inline int | |
| 235 | ffsl(long mask) | |
| 236 | { | |
| 237 | return (mask == 0 ? mask : (int)bsfq((u_long)mask) + 1); | |
| 238 | } | |
| 239 | ||
| 240 | #define HAVE_INLINE_FLS | |
| 241 | ||
| 242 | static __inline int | |
| 243 | fls(int mask) | |
| 244 | { | |
| 245 | return (mask == 0 ? mask : (int)bsrl((u_int)mask) + 1); | |
| 246 | } | |
| 247 | ||
| 248 | #define HAVE_INLINE_FLSL | |
| 249 | ||
| 250 | static __inline int | |
| 251 | flsl(long mask) | |
| 252 | { | |
| 253 | return (mask == 0 ? mask : (int)bsrq((u_long)mask) + 1); | |
| 254 | } | |
| 255 | ||
| 256 | #endif /* _KERNEL */ | |
| 257 | ||
| 258 | static __inline void | |
| 259 | halt(void) | |
| 260 | { | |
| 261 | __asm __volatile("hlt"); | |
| 262 | } | |
| 263 | ||
| fc3f9779 SS |
264 | /* |
| 265 | * The following complications are to get around gcc not having a | |
| 266 | * constraint letter for the range 0..255. We still put "d" in the | |
| 267 | * constraint because "i" isn't a valid constraint when the port | |
| 268 | * isn't constant. This only matters for -O0 because otherwise | |
| 269 | * the non-working version gets optimized away. | |
| 270 | * | |
| 271 | * Use an expression-statement instead of a conditional expression | |
| 272 | * because gcc-2.6.0 would promote the operands of the conditional | |
| 273 | * and produce poor code for "if ((inb(var) & const1) == const2)". | |
| 274 | * | |
| 275 | * The unnecessary test `(port) < 0x10000' is to generate a warning if | |
| 276 | * the `port' has type u_short or smaller. Such types are pessimal. | |
| 277 | * This actually only works for signed types. The range check is | |
| 278 | * careful to avoid generating warnings. | |
| 279 | */ | |
| 280 | #define inb(port) __extension__ ({ \ | |
| 281 | u_char _data; \ | |
| 282 | if (__builtin_constant_p(port) && ((port) & 0xffff) < 0x100 \ | |
| 283 | && (port) < 0x10000) \ | |
| 284 | _data = inbc(port); \ | |
| 285 | else \ | |
| 286 | _data = inbv(port); \ | |
| 287 | _data; }) | |
| 288 | ||
| 289 | #define outb(port, data) ( \ | |
| 290 | __builtin_constant_p(port) && ((port) & 0xffff) < 0x100 \ | |
| 291 | && (port) < 0x10000 \ | |
| 292 | ? outbc(port, data) : outbv(port, data)) | |
| 293 | ||
| 294 | static __inline u_char | |
| 295 | inbc(u_int port) | |
| 296 | { | |
| 297 | u_char data; | |
| 298 | ||
| 299 | __asm __volatile("inb %1,%0" : "=a" (data) : "id" ((u_short)(port))); | |
| 300 | return (data); | |
| 301 | } | |
| 302 | ||
| 303 | static __inline void | |
| 304 | outbc(u_int port, u_char data) | |
| 305 | { | |
| 306 | __asm __volatile("outb %0,%1" : : "a" (data), "id" ((u_short)(port))); | |
| 307 | } | |
| 308 | ||
| fc3f9779 SS |
309 | static __inline u_char |
| 310 | inbv(u_int port) | |
| 311 | { | |
| 312 | u_char data; | |
| 313 | /* | |
| 314 | * We use %%dx and not %1 here because i/o is done at %dx and not at | |
| 315 | * %edx, while gcc generates inferior code (movw instead of movl) | |
| 316 | * if we tell it to load (u_short) port. | |
| 317 | */ | |
| 318 | __asm __volatile("inb %%dx,%0" : "=a" (data) : "d" (port)); | |
| 319 | return (data); | |
| 320 | } | |
| 321 | ||
| 322 | static __inline u_int | |
| 323 | inl(u_int port) | |
| 324 | { | |
| 325 | u_int data; | |
| 326 | ||
| 327 | __asm __volatile("inl %%dx,%0" : "=a" (data) : "d" (port)); | |
| 328 | return (data); | |
| 329 | } | |
| 330 | ||
| 331 | static __inline void | |
| 332 | insb(u_int port, void *addr, size_t cnt) | |
| 333 | { | |
| 334 | __asm __volatile("cld; rep; insb" | |
| 335 | : "+D" (addr), "+c" (cnt) | |
| 336 | : "d" (port) | |
| 337 | : "memory"); | |
| 338 | } | |
| 339 | ||
| 340 | static __inline void | |
| 341 | insw(u_int port, void *addr, size_t cnt) | |
| 342 | { | |
| 343 | __asm __volatile("cld; rep; insw" | |
| 344 | : "+D" (addr), "+c" (cnt) | |
| 345 | : "d" (port) | |
| 346 | : "memory"); | |
| 347 | } | |
| 348 | ||
| 349 | static __inline void | |
| 350 | insl(u_int port, void *addr, size_t cnt) | |
| 351 | { | |
| 352 | __asm __volatile("cld; rep; insl" | |
| 353 | : "+D" (addr), "+c" (cnt) | |
| 354 | : "d" (port) | |
| 355 | : "memory"); | |
| 356 | } | |
| 357 | ||
| 358 | static __inline void | |
| 359 | invd(void) | |
| 360 | { | |
| 361 | __asm __volatile("invd"); | |
| 362 | } | |
| 363 | ||
| c8fe38ae MD |
364 | #if defined(_KERNEL) |
| 365 | ||
| 366 | /* | |
| 367 | * If we are not a true-SMP box then smp_invltlb() is a NOP. Note that this | |
| 368 | * will cause the invl*() functions to be equivalent to the cpu_invl*() | |
| 369 | * functions. | |
| 370 | */ | |
| 371 | #ifdef SMP | |
| 372 | void smp_invltlb(void); | |
| 373 | #else | |
| 374 | #define smp_invltlb() | |
| 375 | #endif | |
| 376 | ||
| 377 | #ifndef _CPU_INVLPG_DEFINED | |
| 378 | ||
| 379 | /* | |
| 380 | * Invalidate a patricular VA on this cpu only | |
| 381 | */ | |
| 382 | static __inline void | |
| 383 | cpu_invlpg(void *addr) | |
| 384 | { | |
| 385 | __asm __volatile("invlpg %0" : : "m" (*(char *)addr) : "memory"); | |
| 386 | } | |
| 387 | ||
| 388 | #endif | |
| 389 | ||
| 3b681182 SS |
390 | static __inline void |
| 391 | cpu_nop(void) | |
| 392 | { | |
| 393 | __asm __volatile("rep; nop"); | |
| 394 | } | |
| 395 | ||
| c8fe38ae MD |
396 | #endif /* _KERNEL */ |
| 397 | ||
| fc3f9779 SS |
398 | static __inline u_short |
| 399 | inw(u_int port) | |
| 400 | { | |
| 401 | u_short data; | |
| 402 | ||
| 403 | __asm __volatile("inw %%dx,%0" : "=a" (data) : "d" (port)); | |
| 404 | return (data); | |
| 405 | } | |
| 406 | ||
| d7f50089 YY |
407 | static __inline u_int |
| 408 | loadandclear(volatile u_int *addr) | |
| 409 | { | |
| 410 | u_int result; | |
| 411 | ||
| 412 | __asm __volatile("xorl %0,%0; xchgl %1,%0" | |
| 413 | : "=&r" (result) : "m" (*addr)); | |
| 414 | return (result); | |
| 415 | } | |
| 416 | ||
| fc3f9779 SS |
417 | static __inline void |
| 418 | outbv(u_int port, u_char data) | |
| 419 | { | |
| 420 | u_char al; | |
| 421 | /* | |
| 422 | * Use an unnecessary assignment to help gcc's register allocator. | |
| 423 | * This make a large difference for gcc-1.40 and a tiny difference | |
| 424 | * for gcc-2.6.0. For gcc-1.40, al had to be ``asm("ax")'' for | |
| 425 | * best results. gcc-2.6.0 can't handle this. | |
| 426 | */ | |
| 427 | al = data; | |
| 428 | __asm __volatile("outb %0,%%dx" : : "a" (al), "d" (port)); | |
| 429 | } | |
| 430 | ||
| 431 | static __inline void | |
| 432 | outl(u_int port, u_int data) | |
| 433 | { | |
| 434 | /* | |
| 435 | * outl() and outw() aren't used much so we haven't looked at | |
| 436 | * possible micro-optimizations such as the unnecessary | |
| 437 | * assignment for them. | |
| 438 | */ | |
| 439 | __asm __volatile("outl %0,%%dx" : : "a" (data), "d" (port)); | |
| 440 | } | |
| 441 | ||
| 442 | static __inline void | |
| 443 | outsb(u_int port, const void *addr, size_t cnt) | |
| 444 | { | |
| 445 | __asm __volatile("cld; rep; outsb" | |
| 446 | : "+S" (addr), "+c" (cnt) | |
| 447 | : "d" (port)); | |
| 448 | } | |
| 449 | ||
| 450 | static __inline void | |
| 451 | outsw(u_int port, const void *addr, size_t cnt) | |
| 452 | { | |
| 453 | __asm __volatile("cld; rep; outsw" | |
| 454 | : "+S" (addr), "+c" (cnt) | |
| 455 | : "d" (port)); | |
| 456 | } | |
| 457 | ||
| 458 | static __inline void | |
| 459 | outsl(u_int port, const void *addr, size_t cnt) | |
| 460 | { | |
| 461 | __asm __volatile("cld; rep; outsl" | |
| 462 | : "+S" (addr), "+c" (cnt) | |
| 463 | : "d" (port)); | |
| 464 | } | |
| 465 | ||
| 466 | static __inline void | |
| 467 | outw(u_int port, u_short data) | |
| 468 | { | |
| 469 | __asm __volatile("outw %0,%%dx" : : "a" (data), "d" (port)); | |
| 470 | } | |
| 471 | ||
| 472 | static __inline void | |
| 473 | ia32_pause(void) | |
| 474 | { | |
| 475 | __asm __volatile("pause"); | |
| 476 | } | |
| 477 | ||
| 478 | static __inline u_long | |
| 479 | read_rflags(void) | |
| 480 | { | |
| 481 | u_long rf; | |
| 482 | ||
| 483 | __asm __volatile("pushfq; popq %0" : "=r" (rf)); | |
| 484 | return (rf); | |
| 485 | } | |
| 486 | ||
| 487 | static __inline u_int64_t | |
| 488 | rdmsr(u_int msr) | |
| 489 | { | |
| 490 | u_int32_t low, high; | |
| 491 | ||
| 492 | __asm __volatile("rdmsr" : "=a" (low), "=d" (high) : "c" (msr)); | |
| 493 | return (low | ((u_int64_t)high << 32)); | |
| 494 | } | |
| 495 | ||
| 496 | static __inline u_int64_t | |
| 497 | rdpmc(u_int pmc) | |
| 498 | { | |
| 499 | u_int32_t low, high; | |
| 500 | ||
| 501 | __asm __volatile("rdpmc" : "=a" (low), "=d" (high) : "c" (pmc)); | |
| 502 | return (low | ((u_int64_t)high << 32)); | |
| 503 | } | |
| 504 | ||
| 2e537993 MD |
505 | #define _RDTSC_SUPPORTED_ |
| 506 | ||
| fc3f9779 SS |
507 | static __inline u_int64_t |
| 508 | rdtsc(void) | |
| 509 | { | |
| 510 | u_int32_t low, high; | |
| 511 | ||
| 512 | __asm __volatile("rdtsc" : "=a" (low), "=d" (high)); | |
| 513 | return (low | ((u_int64_t)high << 32)); | |
| 514 | } | |
| 515 | ||
| 516 | static __inline void | |
| 517 | wbinvd(void) | |
| 518 | { | |
| 519 | __asm __volatile("wbinvd"); | |
| 520 | } | |
| 521 | ||
| 522 | static __inline void | |
| 523 | write_rflags(u_long rf) | |
| 524 | { | |
| 525 | __asm __volatile("pushq %0; popfq" : : "r" (rf)); | |
| 526 | } | |
| 527 | ||
| 528 | static __inline void | |
| 529 | wrmsr(u_int msr, u_int64_t newval) | |
| 530 | { | |
| 531 | u_int32_t low, high; | |
| 532 | ||
| 533 | low = newval; | |
| 534 | high = newval >> 32; | |
| 535 | __asm __volatile("wrmsr" : : "a" (low), "d" (high), "c" (msr)); | |
| 536 | } | |
| 537 | ||
| 538 | static __inline void | |
| 539 | load_cr0(u_long data) | |
| 540 | { | |
| 541 | ||
| 542 | __asm __volatile("movq %0,%%cr0" : : "r" (data)); | |
| 543 | } | |
| 544 | ||
| 545 | static __inline u_long | |
| 546 | rcr0(void) | |
| 547 | { | |
| 548 | u_long data; | |
| 549 | ||
| 550 | __asm __volatile("movq %%cr0,%0" : "=r" (data)); | |
| 551 | return (data); | |
| 552 | } | |
| 553 | ||
| 554 | static __inline u_long | |
| 555 | rcr2(void) | |
| 556 | { | |
| 557 | u_long data; | |
| 558 | ||
| 559 | __asm __volatile("movq %%cr2,%0" : "=r" (data)); | |
| 560 | return (data); | |
| 561 | } | |
| 562 | ||
| 563 | static __inline void | |
| 564 | load_cr3(u_long data) | |
| 565 | { | |
| 566 | ||
| 567 | __asm __volatile("movq %0,%%cr3" : : "r" (data) : "memory"); | |
| 568 | } | |
| 569 | ||
| 570 | static __inline u_long | |
| 571 | rcr3(void) | |
| 572 | { | |
| 573 | u_long data; | |
| 574 | ||
| 575 | __asm __volatile("movq %%cr3,%0" : "=r" (data)); | |
| 576 | return (data); | |
| 577 | } | |
| 578 | ||
| 579 | static __inline void | |
| 580 | load_cr4(u_long data) | |
| 581 | { | |
| 582 | __asm __volatile("movq %0,%%cr4" : : "r" (data)); | |
| 583 | } | |
| 584 | ||
| 585 | static __inline u_long | |
| 586 | rcr4(void) | |
| 587 | { | |
| 588 | u_long data; | |
| 589 | ||
| 590 | __asm __volatile("movq %%cr4,%0" : "=r" (data)); | |
| 591 | return (data); | |
| 592 | } | |
| 593 | ||
| 594 | /* | |
| 595 | * Global TLB flush (except for thise for pages marked PG_G) | |
| 596 | */ | |
| 597 | static __inline void | |
| c8fe38ae | 598 | cpu_invltlb(void) |
| fc3f9779 SS |
599 | { |
| 600 | ||
| 601 | load_cr3(rcr3()); | |
| 602 | } | |
| 603 | ||
| 604 | /* | |
| 605 | * TLB flush for an individual page (even if it has PG_G). | |
| 606 | * Only works on 486+ CPUs (i386 does not have PG_G). | |
| 607 | */ | |
| 608 | static __inline void | |
| 609 | invlpg(u_long addr) | |
| 610 | { | |
| 611 | ||
| 612 | __asm __volatile("invlpg %0" : : "m" (*(char *)addr) : "memory"); | |
| 613 | } | |
| 614 | ||
| 615 | static __inline u_int | |
| 616 | rfs(void) | |
| 617 | { | |
| 618 | u_int sel; | |
| 619 | __asm __volatile("movl %%fs,%0" : "=rm" (sel)); | |
| 620 | return (sel); | |
| 621 | } | |
| 622 | ||
| 623 | static __inline u_int | |
| 624 | rgs(void) | |
| 625 | { | |
| 626 | u_int sel; | |
| 627 | __asm __volatile("movl %%gs,%0" : "=rm" (sel)); | |
| 628 | return (sel); | |
| 629 | } | |
| 630 | ||
| 631 | static __inline void | |
| 632 | load_ds(u_int sel) | |
| 633 | { | |
| 634 | __asm __volatile("movl %0,%%ds" : : "rm" (sel)); | |
| 635 | } | |
| 636 | ||
| 637 | static __inline void | |
| 638 | load_es(u_int sel) | |
| 639 | { | |
| 640 | __asm __volatile("movl %0,%%es" : : "rm" (sel)); | |
| 641 | } | |
| 642 | ||
| 643 | #ifdef _KERNEL | |
| 644 | /* This is defined in <machine/specialreg.h> but is too painful to get to */ | |
| 645 | #ifndef MSR_FSBASE | |
| 646 | #define MSR_FSBASE 0xc0000100 | |
| 647 | #endif | |
| 648 | static __inline void | |
| 649 | load_fs(u_int sel) | |
| 650 | { | |
| fc3f9779 | 651 | /* Preserve the fsbase value across the selector load */ |
| fc3f9779 | 652 | __asm __volatile("rdmsr; movl %0,%%fs; wrmsr" |
| c4fb66bd | 653 | : : "rm" (sel), "c" (MSR_FSBASE) : "eax", "edx"); |
| fc3f9779 SS |
654 | } |
| 655 | ||
| 656 | #ifndef MSR_GSBASE | |
| 657 | #define MSR_GSBASE 0xc0000101 | |
| 658 | #endif | |
| 659 | static __inline void | |
| 660 | load_gs(u_int sel) | |
| 661 | { | |
| fc3f9779 SS |
662 | /* |
| 663 | * Preserve the gsbase value across the selector load. | |
| 664 | * Note that we have to disable interrupts because the gsbase | |
| 665 | * being trashed happens to be the kernel gsbase at the time. | |
| 666 | */ | |
| c8fe38ae | 667 | __asm __volatile("pushfq; cli; rdmsr; movw %0,%%gs; wrmsr; popfq" |
| c4fb66bd | 668 | : : "rm" (sel), "c" (MSR_GSBASE) : "eax", "edx"); |
| fc3f9779 SS |
669 | } |
| 670 | #else | |
| 671 | /* Usable by userland */ | |
| 672 | static __inline void | |
| 673 | load_fs(u_int sel) | |
| 674 | { | |
| 675 | __asm __volatile("movl %0,%%fs" : : "rm" (sel)); | |
| 676 | } | |
| 677 | ||
| 678 | static __inline void | |
| 679 | load_gs(u_int sel) | |
| 680 | { | |
| 681 | __asm __volatile("movl %0,%%gs" : : "rm" (sel)); | |
| 682 | } | |
| 683 | #endif | |
| 684 | ||
| 685 | /* void lidt(struct region_descriptor *addr); */ | |
| 686 | static __inline void | |
| 687 | lidt(struct region_descriptor *addr) | |
| 688 | { | |
| 689 | __asm __volatile("lidt (%0)" : : "r" (addr)); | |
| 690 | } | |
| 691 | ||
| 692 | /* void lldt(u_short sel); */ | |
| 693 | static __inline void | |
| 694 | lldt(u_short sel) | |
| 695 | { | |
| 696 | __asm __volatile("lldt %0" : : "r" (sel)); | |
| 697 | } | |
| 698 | ||
| 699 | /* void ltr(u_short sel); */ | |
| 700 | static __inline void | |
| 701 | ltr(u_short sel) | |
| 702 | { | |
| 703 | __asm __volatile("ltr %0" : : "r" (sel)); | |
| 704 | } | |
| 705 | ||
| 706 | static __inline u_int64_t | |
| 707 | rdr0(void) | |
| 708 | { | |
| 709 | u_int64_t data; | |
| 710 | __asm __volatile("movq %%dr0,%0" : "=r" (data)); | |
| 711 | return (data); | |
| 712 | } | |
| 713 | ||
| 714 | static __inline void | |
| 715 | load_dr0(u_int64_t dr0) | |
| 716 | { | |
| 717 | __asm __volatile("movq %0,%%dr0" : : "r" (dr0)); | |
| 718 | } | |
| 719 | ||
| 720 | static __inline u_int64_t | |
| 721 | rdr1(void) | |
| 722 | { | |
| 723 | u_int64_t data; | |
| 724 | __asm __volatile("movq %%dr1,%0" : "=r" (data)); | |
| 725 | return (data); | |
| 726 | } | |
| 727 | ||
| 728 | static __inline void | |
| 729 | load_dr1(u_int64_t dr1) | |
| 730 | { | |
| 731 | __asm __volatile("movq %0,%%dr1" : : "r" (dr1)); | |
| 732 | } | |
| 733 | ||
| 734 | static __inline u_int64_t | |
| 735 | rdr2(void) | |
| 736 | { | |
| 737 | u_int64_t data; | |
| 738 | __asm __volatile("movq %%dr2,%0" : "=r" (data)); | |
| 739 | return (data); | |
| 740 | } | |
| 741 | ||
| 742 | static __inline void | |
| 743 | load_dr2(u_int64_t dr2) | |
| 744 | { | |
| 745 | __asm __volatile("movq %0,%%dr2" : : "r" (dr2)); | |
| 746 | } | |
| 747 | ||
| 748 | static __inline u_int64_t | |
| 749 | rdr3(void) | |
| 750 | { | |
| 751 | u_int64_t data; | |
| 752 | __asm __volatile("movq %%dr3,%0" : "=r" (data)); | |
| 753 | return (data); | |
| 754 | } | |
| 755 | ||
| 756 | static __inline void | |
| 757 | load_dr3(u_int64_t dr3) | |
| 758 | { | |
| 759 | __asm __volatile("movq %0,%%dr3" : : "r" (dr3)); | |
| 760 | } | |
| 761 | ||
| 762 | static __inline u_int64_t | |
| 763 | rdr4(void) | |
| 764 | { | |
| 765 | u_int64_t data; | |
| 766 | __asm __volatile("movq %%dr4,%0" : "=r" (data)); | |
| 767 | return (data); | |
| 768 | } | |
| 769 | ||
| 770 | static __inline void | |
| 771 | load_dr4(u_int64_t dr4) | |
| 772 | { | |
| 773 | __asm __volatile("movq %0,%%dr4" : : "r" (dr4)); | |
| 774 | } | |
| 775 | ||
| 776 | static __inline u_int64_t | |
| 777 | rdr5(void) | |
| 778 | { | |
| 779 | u_int64_t data; | |
| 780 | __asm __volatile("movq %%dr5,%0" : "=r" (data)); | |
| 781 | return (data); | |
| 782 | } | |
| 783 | ||
| 784 | static __inline void | |
| 785 | load_dr5(u_int64_t dr5) | |
| 786 | { | |
| 787 | __asm __volatile("movq %0,%%dr5" : : "r" (dr5)); | |
| 788 | } | |
| 789 | ||
| 790 | static __inline u_int64_t | |
| 791 | rdr6(void) | |
| 792 | { | |
| 793 | u_int64_t data; | |
| 794 | __asm __volatile("movq %%dr6,%0" : "=r" (data)); | |
| 795 | return (data); | |
| 796 | } | |
| 797 | ||
| 798 | static __inline void | |
| 799 | load_dr6(u_int64_t dr6) | |
| 800 | { | |
| 801 | __asm __volatile("movq %0,%%dr6" : : "r" (dr6)); | |
| 802 | } | |
| 803 | ||
| 804 | static __inline u_int64_t | |
| 805 | rdr7(void) | |
| 806 | { | |
| 807 | u_int64_t data; | |
| 808 | __asm __volatile("movq %%dr7,%0" : "=r" (data)); | |
| 809 | return (data); | |
| 810 | } | |
| 811 | ||
| 812 | static __inline void | |
| 813 | load_dr7(u_int64_t dr7) | |
| 814 | { | |
| 815 | __asm __volatile("movq %0,%%dr7" : : "r" (dr7)); | |
| 816 | } | |
| 817 | ||
| 818 | static __inline register_t | |
| 819 | intr_disable(void) | |
| 820 | { | |
| 821 | register_t rflags; | |
| 822 | ||
| 823 | rflags = read_rflags(); | |
| c8fe38ae | 824 | cpu_disable_intr(); |
| fc3f9779 SS |
825 | return (rflags); |
| 826 | } | |
| 827 | ||
| 828 | static __inline void | |
| 829 | intr_restore(register_t rflags) | |
| 830 | { | |
| 831 | write_rflags(rflags); | |
| 832 | } | |
| 833 | ||
| 834 | #else /* !__GNUC__ */ | |
| 835 | ||
| 836 | int breakpoint(void); | |
| d7f50089 | 837 | void cpu_pause(void); |
| fc3f9779 SS |
838 | u_int bsfl(u_int mask); |
| 839 | u_int bsrl(u_int mask); | |
| c8fe38ae MD |
840 | void cpu_disable_intr(void); |
| 841 | void cpu_enable_intr(void); | |
| fc3f9779 SS |
842 | void cpu_invlpg(u_long addr); |
| 843 | void cpu_invlpg_range(u_long start, u_long end); | |
| fc3f9779 | 844 | void do_cpuid(u_int ax, u_int *p); |
| fc3f9779 SS |
845 | void halt(void); |
| 846 | u_char inb(u_int port); | |
| 847 | u_int inl(u_int port); | |
| 848 | void insb(u_int port, void *addr, size_t cnt); | |
| 849 | void insl(u_int port, void *addr, size_t cnt); | |
| 850 | void insw(u_int port, void *addr, size_t cnt); | |
| 851 | void invd(void); | |
| 852 | void invlpg(u_int addr); | |
| 853 | void invlpg_range(u_int start, u_int end); | |
| c8fe38ae | 854 | void cpu_invltlb(void); |
| fc3f9779 SS |
855 | u_short inw(u_int port); |
| 856 | void load_cr0(u_int cr0); | |
| 857 | void load_cr3(u_int cr3); | |
| 858 | void load_cr4(u_int cr4); | |
| 859 | void load_fs(u_int sel); | |
| 860 | void load_gs(u_int sel); | |
| 861 | struct region_descriptor; | |
| 862 | void lidt(struct region_descriptor *addr); | |
| 863 | void lldt(u_short sel); | |
| 864 | void ltr(u_short sel); | |
| 865 | void outb(u_int port, u_char data); | |
| 866 | void outl(u_int port, u_int data); | |
| 867 | void outsb(u_int port, void *addr, size_t cnt); | |
| 868 | void outsl(u_int port, void *addr, size_t cnt); | |
| 869 | void outsw(u_int port, void *addr, size_t cnt); | |
| 870 | void outw(u_int port, u_short data); | |
| 871 | void ia32_pause(void); | |
| 872 | u_int rcr0(void); | |
| 873 | u_int rcr2(void); | |
| 874 | u_int rcr3(void); | |
| 875 | u_int rcr4(void); | |
| 876 | u_int rfs(void); | |
| 877 | u_int rgs(void); | |
| 878 | u_int64_t rdmsr(u_int msr); | |
| 879 | u_int64_t rdpmc(u_int pmc); | |
| 880 | u_int64_t rdtsc(void); | |
| 881 | u_int read_rflags(void); | |
| 882 | void wbinvd(void); | |
| 883 | void write_rflags(u_int rf); | |
| 884 | void wrmsr(u_int msr, u_int64_t newval); | |
| 885 | u_int64_t rdr0(void); | |
| 886 | void load_dr0(u_int64_t dr0); | |
| 887 | u_int64_t rdr1(void); | |
| 888 | void load_dr1(u_int64_t dr1); | |
| 889 | u_int64_t rdr2(void); | |
| 890 | void load_dr2(u_int64_t dr2); | |
| 891 | u_int64_t rdr3(void); | |
| 892 | void load_dr3(u_int64_t dr3); | |
| 893 | u_int64_t rdr4(void); | |
| 894 | void load_dr4(u_int64_t dr4); | |
| 895 | u_int64_t rdr5(void); | |
| 896 | void load_dr5(u_int64_t dr5); | |
| 897 | u_int64_t rdr6(void); | |
| 898 | void load_dr6(u_int64_t dr6); | |
| 899 | u_int64_t rdr7(void); | |
| 900 | void load_dr7(u_int64_t dr7); | |
| 901 | register_t intr_disable(void); | |
| 902 | void intr_restore(register_t rf); | |
| 903 | ||
| 904 | #endif /* __GNUC__ */ | |
| 905 | ||
| 906 | void reset_dbregs(void); | |
| 907 | ||
| 908 | __END_DECLS | |
| 909 | ||
| 910 | #endif /* !_CPU_CPUFUNC_H_ */ |