1 /*- 2 * Copyright (c) 2003 Peter Wemm. 3 * Copyright (c) 1993 The Regents of the University of California. 4 * Copyright (c) 2008 The DragonFly Project. 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 $ 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 <sys/thread.h> 49 #include <machine/psl.h> 50 #include <machine/smp.h> 51 52 struct thread; 53 struct region_descriptor; 54 55 __BEGIN_DECLS 56 #define readb(va) (*(volatile u_int8_t *) (va)) 57 #define readw(va) (*(volatile u_int16_t *) (va)) 58 #define readl(va) (*(volatile u_int32_t *) (va)) 59 #define readq(va) (*(volatile u_int64_t *) (va)) 60 61 #define writeb(va, d) (*(volatile u_int8_t *) (va) = (d)) 62 #define writew(va, d) (*(volatile u_int16_t *) (va) = (d)) 63 #define writel(va, d) (*(volatile u_int32_t *) (va) = (d)) 64 #define writeq(va, d) (*(volatile u_int64_t *) (va) = (d)) 65 66 #ifdef __GNUC__ 67 68 #include <machine/lock.h> /* XXX */ 69 70 static __inline void 71 breakpoint(void) 72 { 73 __asm __volatile("int $3"); 74 } 75 76 static __inline void 77 cpu_pause(void) 78 { 79 __asm __volatile("pause"); 80 } 81 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_long 101 bsflong(u_long mask) 102 { 103 u_long result; 104 105 __asm __volatile("bsfq %1,%0" : "=r" (result) : "rm" (mask)); 106 return (result); 107 } 108 109 static __inline u_int 110 bsrl(u_int mask) 111 { 112 u_int result; 113 114 __asm __volatile("bsrl %1,%0" : "=r" (result) : "rm" (mask)); 115 return (result); 116 } 117 118 static __inline u_long 119 bsrq(u_long mask) 120 { 121 u_long result; 122 123 __asm __volatile("bsrq %1,%0" : "=r" (result) : "rm" (mask)); 124 return (result); 125 } 126 127 static __inline void 128 clflush(u_long addr) 129 { 130 __asm __volatile("clflush %0" : : "m" (*(char *) addr)); 131 } 132 133 static __inline void 134 do_cpuid(u_int ax, u_int *p) 135 { 136 __asm __volatile("cpuid" 137 : "=a" (p[0]), "=b" (p[1]), "=c" (p[2]), "=d" (p[3]) 138 : "0" (ax)); 139 } 140 141 static __inline void 142 cpuid_count(u_int ax, u_int cx, u_int *p) 143 { 144 __asm __volatile("cpuid" 145 : "=a" (p[0]), "=b" (p[1]), "=c" (p[2]), "=d" (p[3]) 146 : "0" (ax), "c" (cx)); 147 } 148 149 #ifndef _CPU_DISABLE_INTR_DEFINED 150 151 static __inline void 152 cpu_disable_intr(void) 153 { 154 __asm __volatile("cli" : : : "memory"); 155 } 156 157 #endif 158 159 #ifndef _CPU_ENABLE_INTR_DEFINED 160 161 static __inline void 162 cpu_enable_intr(void) 163 { 164 __asm __volatile("sti"); 165 } 166 167 #endif 168 169 /* 170 * Cpu and compiler memory ordering fence. mfence ensures strong read and 171 * write ordering. 172 * 173 * A serializing or fence instruction is required here. A locked bus 174 * cycle on data for which we already own cache mastership is the most 175 * portable. 176 */ 177 static __inline void 178 cpu_mfence(void) 179 { 180 __asm __volatile("mfence" : : : "memory"); 181 } 182 183 /* 184 * cpu_lfence() ensures strong read ordering for reads issued prior 185 * to the instruction verses reads issued afterwords. 186 * 187 * A serializing or fence instruction is required here. A locked bus 188 * cycle on data for which we already own cache mastership is the most 189 * portable. 190 */ 191 static __inline void 192 cpu_lfence(void) 193 { 194 __asm __volatile("lfence" : : : "memory"); 195 } 196 197 /* 198 * cpu_sfence() ensures strong write ordering for writes issued prior 199 * to the instruction verses writes issued afterwords. Writes are 200 * ordered on intel cpus so we do not actually have to do anything. 201 */ 202 static __inline void 203 cpu_sfence(void) 204 { 205 /* 206 * NOTE: 207 * Don't use 'sfence' here, as it will create a lot of 208 * unnecessary stalls. 209 */ 210 __asm __volatile("" : : : "memory"); 211 } 212 213 /* 214 * cpu_ccfence() prevents the compiler from reordering instructions, in 215 * particular stores, relative to the current cpu. Use cpu_sfence() if 216 * you need to guarentee ordering by both the compiler and by the cpu. 217 * 218 * This also prevents the compiler from caching memory loads into local 219 * variables across the routine. 220 */ 221 static __inline void 222 cpu_ccfence(void) 223 { 224 __asm __volatile("" : : : "memory"); 225 } 226 227 /* 228 * This is a horrible, horrible hack that might have to be put at the 229 * end of certain procedures (on a case by case basis), just before it 230 * returns to avoid what we believe to be an unreported AMD cpu bug. 231 * Found to occur on both a Phenom II X4 820 (two of them), as well 232 * as a 48-core built around an Opteron 6168 (Id = 0x100f91 Stepping = 1). 233 * The problem does not appear to occur w/Intel cpus. 234 * 235 * The bug is likely related to either a write combining issue or the 236 * Return Address Stack (RAS) hardware cache. 237 * 238 * In particular, we had to do this for GCC's fill_sons_in_loop() routine 239 * which due to its deep recursion and stack flow appears to be able to 240 * tickle the amd cpu bug (w/ gcc-4.4.7). Adding a single 'nop' to the 241 * end of the routine just before it returns works around the bug. 242 * 243 * The bug appears to be extremely sensitive to %rip and %rsp values, to 244 * the point where even just inserting an instruction in an unrelated 245 * procedure (shifting the entire code base being run) effects the outcome. 246 * DragonFly is probably able to more readily reproduce the bug due to 247 * the stackgap randomization code. We would expect OpenBSD (where we got 248 * the stackgap randomization code from) to also be able to reproduce the 249 * issue. To date we have only reproduced the issue in DragonFly. 250 */ 251 #define __AMDCPUBUG_DFLY01_AVAILABLE__ 252 253 static __inline void 254 cpu_amdcpubug_dfly01(void) 255 { 256 __asm __volatile("nop" : : : "memory"); 257 } 258 259 #ifdef _KERNEL 260 261 #define HAVE_INLINE_FFS 262 263 static __inline int 264 ffs(int mask) 265 { 266 #if 0 267 /* 268 * Note that gcc-2's builtin ffs would be used if we didn't declare 269 * this inline or turn off the builtin. The builtin is faster but 270 * broken in gcc-2.4.5 and slower but working in gcc-2.5 and later 271 * versions. 272 */ 273 return (mask == 0 ? mask : (int)bsfl((u_int)mask) + 1); 274 #else 275 /* Actually, the above is way out of date. The builtins use cmov etc */ 276 return (__builtin_ffs(mask)); 277 #endif 278 } 279 280 #define HAVE_INLINE_FFSL 281 282 static __inline int 283 ffsl(long mask) 284 { 285 return (mask == 0 ? mask : (int)bsfq((u_long)mask) + 1); 286 } 287 288 #define HAVE_INLINE_FLS 289 290 static __inline int 291 fls(int mask) 292 { 293 return (mask == 0 ? mask : (int)bsrl((u_int)mask) + 1); 294 } 295 296 #define HAVE_INLINE_FLSL 297 298 static __inline int 299 flsl(long mask) 300 { 301 return (mask == 0 ? mask : (int)bsrq((u_long)mask) + 1); 302 } 303 304 #endif /* _KERNEL */ 305 306 static __inline void 307 halt(void) 308 { 309 __asm __volatile("hlt"); 310 } 311 312 /* 313 * The following complications are to get around gcc not having a 314 * constraint letter for the range 0..255. We still put "d" in the 315 * constraint because "i" isn't a valid constraint when the port 316 * isn't constant. This only matters for -O0 because otherwise 317 * the non-working version gets optimized away. 318 * 319 * Use an expression-statement instead of a conditional expression 320 * because gcc-2.6.0 would promote the operands of the conditional 321 * and produce poor code for "if ((inb(var) & const1) == const2)". 322 * 323 * The unnecessary test `(port) < 0x10000' is to generate a warning if 324 * the `port' has type u_short or smaller. Such types are pessimal. 325 * This actually only works for signed types. The range check is 326 * careful to avoid generating warnings. 327 */ 328 #define inb(port) __extension__ ({ \ 329 u_char _data; \ 330 if (__builtin_constant_p(port) && ((port) & 0xffff) < 0x100 \ 331 && (port) < 0x10000) \ 332 _data = inbc(port); \ 333 else \ 334 _data = inbv(port); \ 335 _data; }) 336 337 #define outb(port, data) ( \ 338 __builtin_constant_p(port) && ((port) & 0xffff) < 0x100 \ 339 && (port) < 0x10000 \ 340 ? outbc(port, data) : outbv(port, data)) 341 342 static __inline u_char 343 inbc(u_int port) 344 { 345 u_char data; 346 347 __asm __volatile("inb %1,%0" : "=a" (data) : "id" ((u_short)(port))); 348 return (data); 349 } 350 351 static __inline void 352 outbc(u_int port, u_char data) 353 { 354 __asm __volatile("outb %0,%1" : : "a" (data), "id" ((u_short)(port))); 355 } 356 357 static __inline u_char 358 inbv(u_int port) 359 { 360 u_char data; 361 /* 362 * We use %%dx and not %1 here because i/o is done at %dx and not at 363 * %edx, while gcc generates inferior code (movw instead of movl) 364 * if we tell it to load (u_short) port. 365 */ 366 __asm __volatile("inb %%dx,%0" : "=a" (data) : "d" (port)); 367 return (data); 368 } 369 370 static __inline u_int 371 inl(u_int port) 372 { 373 u_int data; 374 375 __asm __volatile("inl %%dx,%0" : "=a" (data) : "d" (port)); 376 return (data); 377 } 378 379 static __inline void 380 insb(u_int port, void *addr, size_t cnt) 381 { 382 __asm __volatile("cld; rep; insb" 383 : "+D" (addr), "+c" (cnt) 384 : "d" (port) 385 : "memory"); 386 } 387 388 static __inline void 389 insw(u_int port, void *addr, size_t cnt) 390 { 391 __asm __volatile("cld; rep; insw" 392 : "+D" (addr), "+c" (cnt) 393 : "d" (port) 394 : "memory"); 395 } 396 397 static __inline void 398 insl(u_int port, void *addr, size_t cnt) 399 { 400 __asm __volatile("cld; rep; insl" 401 : "+D" (addr), "+c" (cnt) 402 : "d" (port) 403 : "memory"); 404 } 405 406 static __inline void 407 invd(void) 408 { 409 __asm __volatile("invd"); 410 } 411 412 #if defined(_KERNEL) 413 414 /* 415 * If we are not a true-SMP box then smp_invltlb() is a NOP. Note that this 416 * will cause the invl*() functions to be equivalent to the cpu_invl*() 417 * functions. 418 */ 419 void smp_invltlb(void); 420 void smp_invltlb_intr(void); 421 422 #ifndef _CPU_INVLPG_DEFINED 423 424 /* 425 * Invalidate a patricular VA on this cpu only 426 */ 427 static __inline void 428 cpu_invlpg(void *addr) 429 { 430 __asm __volatile("invlpg %0" : : "m" (*(char *)addr) : "memory"); 431 } 432 433 #endif 434 435 static __inline void 436 cpu_nop(void) 437 { 438 __asm __volatile("rep; nop"); 439 } 440 441 #endif /* _KERNEL */ 442 443 static __inline u_short 444 inw(u_int port) 445 { 446 u_short data; 447 448 __asm __volatile("inw %%dx,%0" : "=a" (data) : "d" (port)); 449 return (data); 450 } 451 452 static __inline u_int 453 loadandclear(volatile u_int *addr) 454 { 455 u_int result; 456 457 __asm __volatile("xorl %0,%0; xchgl %1,%0" 458 : "=&r" (result) : "m" (*addr)); 459 return (result); 460 } 461 462 static __inline void 463 outbv(u_int port, u_char data) 464 { 465 u_char al; 466 /* 467 * Use an unnecessary assignment to help gcc's register allocator. 468 * This make a large difference for gcc-1.40 and a tiny difference 469 * for gcc-2.6.0. For gcc-1.40, al had to be ``asm("ax")'' for 470 * best results. gcc-2.6.0 can't handle this. 471 */ 472 al = data; 473 __asm __volatile("outb %0,%%dx" : : "a" (al), "d" (port)); 474 } 475 476 static __inline void 477 outl(u_int port, u_int data) 478 { 479 /* 480 * outl() and outw() aren't used much so we haven't looked at 481 * possible micro-optimizations such as the unnecessary 482 * assignment for them. 483 */ 484 __asm __volatile("outl %0,%%dx" : : "a" (data), "d" (port)); 485 } 486 487 static __inline void 488 outsb(u_int port, const void *addr, size_t cnt) 489 { 490 __asm __volatile("cld; rep; outsb" 491 : "+S" (addr), "+c" (cnt) 492 : "d" (port)); 493 } 494 495 static __inline void 496 outsw(u_int port, const void *addr, size_t cnt) 497 { 498 __asm __volatile("cld; rep; outsw" 499 : "+S" (addr), "+c" (cnt) 500 : "d" (port)); 501 } 502 503 static __inline void 504 outsl(u_int port, const void *addr, size_t cnt) 505 { 506 __asm __volatile("cld; rep; outsl" 507 : "+S" (addr), "+c" (cnt) 508 : "d" (port)); 509 } 510 511 static __inline void 512 outw(u_int port, u_short data) 513 { 514 __asm __volatile("outw %0,%%dx" : : "a" (data), "d" (port)); 515 } 516 517 static __inline void 518 ia32_pause(void) 519 { 520 __asm __volatile("pause"); 521 } 522 523 static __inline u_long 524 read_rflags(void) 525 { 526 u_long rf; 527 528 __asm __volatile("pushfq; popq %0" : "=r" (rf)); 529 return (rf); 530 } 531 532 static __inline u_int64_t 533 rdmsr(u_int msr) 534 { 535 u_int32_t low, high; 536 537 __asm __volatile("rdmsr" : "=a" (low), "=d" (high) : "c" (msr)); 538 return (low | ((u_int64_t)high << 32)); 539 } 540 541 static __inline u_int64_t 542 rdpmc(u_int pmc) 543 { 544 u_int32_t low, high; 545 546 __asm __volatile("rdpmc" : "=a" (low), "=d" (high) : "c" (pmc)); 547 return (low | ((u_int64_t)high << 32)); 548 } 549 550 #define _RDTSC_SUPPORTED_ 551 552 static __inline u_int64_t 553 rdtsc(void) 554 { 555 u_int32_t low, high; 556 557 __asm __volatile("rdtsc" : "=a" (low), "=d" (high)); 558 return (low | ((u_int64_t)high << 32)); 559 } 560 561 static __inline void 562 wbinvd(void) 563 { 564 __asm __volatile("wbinvd"); 565 } 566 567 #if defined(_KERNEL) 568 void cpu_wbinvd_on_all_cpus_callback(void *arg); 569 570 static __inline void 571 cpu_wbinvd_on_all_cpus(void) 572 { 573 lwkt_cpusync_simple(smp_active_mask, cpu_wbinvd_on_all_cpus_callback, NULL); 574 } 575 #endif 576 577 static __inline void 578 write_rflags(u_long rf) 579 { 580 __asm __volatile("pushq %0; popfq" : : "r" (rf)); 581 } 582 583 static __inline void 584 wrmsr(u_int msr, u_int64_t newval) 585 { 586 u_int32_t low, high; 587 588 low = newval; 589 high = newval >> 32; 590 __asm __volatile("wrmsr" : : "a" (low), "d" (high), "c" (msr)); 591 } 592 593 static __inline void 594 xsetbv(u_int ecx, u_int eax, u_int edx) 595 { 596 __asm __volatile(".byte 0x0f,0x01,0xd1" 597 : 598 : "a" (eax), "c" (ecx), "d" (edx)); 599 } 600 601 static __inline void 602 load_cr0(u_long data) 603 { 604 605 __asm __volatile("movq %0,%%cr0" : : "r" (data)); 606 } 607 608 static __inline u_long 609 rcr0(void) 610 { 611 u_long data; 612 613 __asm __volatile("movq %%cr0,%0" : "=r" (data)); 614 return (data); 615 } 616 617 static __inline u_long 618 rcr2(void) 619 { 620 u_long data; 621 622 __asm __volatile("movq %%cr2,%0" : "=r" (data)); 623 return (data); 624 } 625 626 static __inline void 627 load_cr3(u_long data) 628 { 629 630 __asm __volatile("movq %0,%%cr3" : : "r" (data) : "memory"); 631 } 632 633 static __inline u_long 634 rcr3(void) 635 { 636 u_long data; 637 638 __asm __volatile("movq %%cr3,%0" : "=r" (data)); 639 return (data); 640 } 641 642 static __inline void 643 load_cr4(u_long data) 644 { 645 __asm __volatile("movq %0,%%cr4" : : "r" (data)); 646 } 647 648 static __inline u_long 649 rcr4(void) 650 { 651 u_long data; 652 653 __asm __volatile("movq %%cr4,%0" : "=r" (data)); 654 return (data); 655 } 656 657 #ifndef _CPU_INVLTLB_DEFINED 658 659 /* 660 * Invalidate the TLB on this cpu only 661 */ 662 static __inline void 663 cpu_invltlb(void) 664 { 665 load_cr3(rcr3()); 666 #if defined(SWTCH_OPTIM_STATS) 667 ++tlb_flush_count; 668 #endif 669 } 670 671 #endif 672 673 /* 674 * TLB flush for an individual page (even if it has PG_G). 675 * Only works on 486+ CPUs (i386 does not have PG_G). 676 */ 677 static __inline void 678 invlpg(u_long addr) 679 { 680 681 __asm __volatile("invlpg %0" : : "m" (*(char *)addr) : "memory"); 682 } 683 684 static __inline u_short 685 rfs(void) 686 { 687 u_short sel; 688 __asm __volatile("movw %%fs,%0" : "=rm" (sel)); 689 return (sel); 690 } 691 692 static __inline u_short 693 rgs(void) 694 { 695 u_short sel; 696 __asm __volatile("movw %%gs,%0" : "=rm" (sel)); 697 return (sel); 698 } 699 700 static __inline void 701 load_ds(u_short sel) 702 { 703 __asm __volatile("movw %0,%%ds" : : "rm" (sel)); 704 } 705 706 static __inline void 707 load_es(u_short sel) 708 { 709 __asm __volatile("movw %0,%%es" : : "rm" (sel)); 710 } 711 712 #ifdef _KERNEL 713 /* This is defined in <machine/specialreg.h> but is too painful to get to */ 714 #ifndef MSR_FSBASE 715 #define MSR_FSBASE 0xc0000100 716 #endif 717 static __inline void 718 load_fs(u_short sel) 719 { 720 /* Preserve the fsbase value across the selector load */ 721 __asm __volatile("rdmsr; movw %0,%%fs; wrmsr" 722 : : "rm" (sel), "c" (MSR_FSBASE) : "eax", "edx"); 723 } 724 725 #ifndef MSR_GSBASE 726 #define MSR_GSBASE 0xc0000101 727 #endif 728 static __inline void 729 load_gs(u_short sel) 730 { 731 /* 732 * Preserve the gsbase value across the selector load. 733 * Note that we have to disable interrupts because the gsbase 734 * being trashed happens to be the kernel gsbase at the time. 735 */ 736 __asm __volatile("pushfq; cli; rdmsr; movw %0,%%gs; wrmsr; popfq" 737 : : "rm" (sel), "c" (MSR_GSBASE) : "eax", "edx"); 738 } 739 #else 740 /* Usable by userland */ 741 static __inline void 742 load_fs(u_short sel) 743 { 744 __asm __volatile("movw %0,%%fs" : : "rm" (sel)); 745 } 746 747 static __inline void 748 load_gs(u_short sel) 749 { 750 __asm __volatile("movw %0,%%gs" : : "rm" (sel)); 751 } 752 #endif 753 754 /* void lidt(struct region_descriptor *addr); */ 755 static __inline void 756 lidt(struct region_descriptor *addr) 757 { 758 __asm __volatile("lidt (%0)" : : "r" (addr)); 759 } 760 761 /* void lldt(u_short sel); */ 762 static __inline void 763 lldt(u_short sel) 764 { 765 __asm __volatile("lldt %0" : : "r" (sel)); 766 } 767 768 /* void ltr(u_short sel); */ 769 static __inline void 770 ltr(u_short sel) 771 { 772 __asm __volatile("ltr %0" : : "r" (sel)); 773 } 774 775 static __inline u_int64_t 776 rdr0(void) 777 { 778 u_int64_t data; 779 __asm __volatile("movq %%dr0,%0" : "=r" (data)); 780 return (data); 781 } 782 783 static __inline void 784 load_dr0(u_int64_t dr0) 785 { 786 __asm __volatile("movq %0,%%dr0" : : "r" (dr0)); 787 } 788 789 static __inline u_int64_t 790 rdr1(void) 791 { 792 u_int64_t data; 793 __asm __volatile("movq %%dr1,%0" : "=r" (data)); 794 return (data); 795 } 796 797 static __inline void 798 load_dr1(u_int64_t dr1) 799 { 800 __asm __volatile("movq %0,%%dr1" : : "r" (dr1)); 801 } 802 803 static __inline u_int64_t 804 rdr2(void) 805 { 806 u_int64_t data; 807 __asm __volatile("movq %%dr2,%0" : "=r" (data)); 808 return (data); 809 } 810 811 static __inline void 812 load_dr2(u_int64_t dr2) 813 { 814 __asm __volatile("movq %0,%%dr2" : : "r" (dr2)); 815 } 816 817 static __inline u_int64_t 818 rdr3(void) 819 { 820 u_int64_t data; 821 __asm __volatile("movq %%dr3,%0" : "=r" (data)); 822 return (data); 823 } 824 825 static __inline void 826 load_dr3(u_int64_t dr3) 827 { 828 __asm __volatile("movq %0,%%dr3" : : "r" (dr3)); 829 } 830 831 static __inline u_int64_t 832 rdr4(void) 833 { 834 u_int64_t data; 835 __asm __volatile("movq %%dr4,%0" : "=r" (data)); 836 return (data); 837 } 838 839 static __inline void 840 load_dr4(u_int64_t dr4) 841 { 842 __asm __volatile("movq %0,%%dr4" : : "r" (dr4)); 843 } 844 845 static __inline u_int64_t 846 rdr5(void) 847 { 848 u_int64_t data; 849 __asm __volatile("movq %%dr5,%0" : "=r" (data)); 850 return (data); 851 } 852 853 static __inline void 854 load_dr5(u_int64_t dr5) 855 { 856 __asm __volatile("movq %0,%%dr5" : : "r" (dr5)); 857 } 858 859 static __inline u_int64_t 860 rdr6(void) 861 { 862 u_int64_t data; 863 __asm __volatile("movq %%dr6,%0" : "=r" (data)); 864 return (data); 865 } 866 867 static __inline void 868 load_dr6(u_int64_t dr6) 869 { 870 __asm __volatile("movq %0,%%dr6" : : "r" (dr6)); 871 } 872 873 static __inline u_int64_t 874 rdr7(void) 875 { 876 u_int64_t data; 877 __asm __volatile("movq %%dr7,%0" : "=r" (data)); 878 return (data); 879 } 880 881 static __inline void 882 load_dr7(u_int64_t dr7) 883 { 884 __asm __volatile("movq %0,%%dr7" : : "r" (dr7)); 885 } 886 887 static __inline register_t 888 intr_disable(void) 889 { 890 register_t rflags; 891 892 rflags = read_rflags(); 893 cpu_disable_intr(); 894 return (rflags); 895 } 896 897 static __inline void 898 intr_restore(register_t rflags) 899 { 900 write_rflags(rflags); 901 } 902 903 #else /* !__GNUC__ */ 904 905 int breakpoint(void); 906 void cpu_pause(void); 907 u_int bsfl(u_int mask); 908 u_int bsrl(u_int mask); 909 void cpu_disable_intr(void); 910 void cpu_enable_intr(void); 911 void cpu_invlpg(u_long addr); 912 void cpu_invlpg_range(u_long start, u_long end); 913 void do_cpuid(u_int ax, u_int *p); 914 void halt(void); 915 u_char inb(u_int port); 916 u_int inl(u_int port); 917 void insb(u_int port, void *addr, size_t cnt); 918 void insl(u_int port, void *addr, size_t cnt); 919 void insw(u_int port, void *addr, size_t cnt); 920 void invd(void); 921 void invlpg(u_int addr); 922 void invlpg_range(u_int start, u_int end); 923 void cpu_invltlb(void); 924 u_short inw(u_int port); 925 void load_cr0(u_int cr0); 926 void load_cr3(u_int cr3); 927 void load_cr4(u_int cr4); 928 void load_fs(u_int sel); 929 void load_gs(u_int sel); 930 struct region_descriptor; 931 void lidt(struct region_descriptor *addr); 932 void lldt(u_short sel); 933 void ltr(u_short sel); 934 void outb(u_int port, u_char data); 935 void outl(u_int port, u_int data); 936 void outsb(u_int port, void *addr, size_t cnt); 937 void outsl(u_int port, void *addr, size_t cnt); 938 void outsw(u_int port, void *addr, size_t cnt); 939 void outw(u_int port, u_short data); 940 void ia32_pause(void); 941 u_int rcr0(void); 942 u_int rcr2(void); 943 u_int rcr3(void); 944 u_int rcr4(void); 945 u_short rfs(void); 946 u_short rgs(void); 947 u_int64_t rdmsr(u_int msr); 948 u_int64_t rdpmc(u_int pmc); 949 u_int64_t rdtsc(void); 950 u_int read_rflags(void); 951 void wbinvd(void); 952 void write_rflags(u_int rf); 953 void wrmsr(u_int msr, u_int64_t newval); 954 u_int64_t rdr0(void); 955 void load_dr0(u_int64_t dr0); 956 u_int64_t rdr1(void); 957 void load_dr1(u_int64_t dr1); 958 u_int64_t rdr2(void); 959 void load_dr2(u_int64_t dr2); 960 u_int64_t rdr3(void); 961 void load_dr3(u_int64_t dr3); 962 u_int64_t rdr4(void); 963 void load_dr4(u_int64_t dr4); 964 u_int64_t rdr5(void); 965 void load_dr5(u_int64_t dr5); 966 u_int64_t rdr6(void); 967 void load_dr6(u_int64_t dr6); 968 u_int64_t rdr7(void); 969 void load_dr7(u_int64_t dr7); 970 register_t intr_disable(void); 971 void intr_restore(register_t rf); 972 973 #endif /* __GNUC__ */ 974 975 int rdmsr_safe(u_int msr, uint64_t *val); 976 void reset_dbregs(void); 977 978 __END_DECLS 979 980 #endif /* !_CPU_CPUFUNC_H_ */ 981