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 load_cr0(u_long data) 595 { 596 597 __asm __volatile("movq %0,%%cr0" : : "r" (data)); 598 } 599 600 static __inline u_long 601 rcr0(void) 602 { 603 u_long data; 604 605 __asm __volatile("movq %%cr0,%0" : "=r" (data)); 606 return (data); 607 } 608 609 static __inline u_long 610 rcr2(void) 611 { 612 u_long data; 613 614 __asm __volatile("movq %%cr2,%0" : "=r" (data)); 615 return (data); 616 } 617 618 static __inline void 619 load_cr3(u_long data) 620 { 621 622 __asm __volatile("movq %0,%%cr3" : : "r" (data) : "memory"); 623 } 624 625 static __inline u_long 626 rcr3(void) 627 { 628 u_long data; 629 630 __asm __volatile("movq %%cr3,%0" : "=r" (data)); 631 return (data); 632 } 633 634 static __inline void 635 load_cr4(u_long data) 636 { 637 __asm __volatile("movq %0,%%cr4" : : "r" (data)); 638 } 639 640 static __inline u_long 641 rcr4(void) 642 { 643 u_long data; 644 645 __asm __volatile("movq %%cr4,%0" : "=r" (data)); 646 return (data); 647 } 648 649 #ifndef _CPU_INVLTLB_DEFINED 650 651 /* 652 * Invalidate the TLB on this cpu only 653 */ 654 static __inline void 655 cpu_invltlb(void) 656 { 657 load_cr3(rcr3()); 658 #if defined(SWTCH_OPTIM_STATS) 659 ++tlb_flush_count; 660 #endif 661 } 662 663 #endif 664 665 /* 666 * TLB flush for an individual page (even if it has PG_G). 667 * Only works on 486+ CPUs (i386 does not have PG_G). 668 */ 669 static __inline void 670 invlpg(u_long addr) 671 { 672 673 __asm __volatile("invlpg %0" : : "m" (*(char *)addr) : "memory"); 674 } 675 676 static __inline u_short 677 rfs(void) 678 { 679 u_short sel; 680 __asm __volatile("movw %%fs,%0" : "=rm" (sel)); 681 return (sel); 682 } 683 684 static __inline u_short 685 rgs(void) 686 { 687 u_short sel; 688 __asm __volatile("movw %%gs,%0" : "=rm" (sel)); 689 return (sel); 690 } 691 692 static __inline void 693 load_ds(u_short sel) 694 { 695 __asm __volatile("movw %0,%%ds" : : "rm" (sel)); 696 } 697 698 static __inline void 699 load_es(u_short sel) 700 { 701 __asm __volatile("movw %0,%%es" : : "rm" (sel)); 702 } 703 704 #ifdef _KERNEL 705 /* This is defined in <machine/specialreg.h> but is too painful to get to */ 706 #ifndef MSR_FSBASE 707 #define MSR_FSBASE 0xc0000100 708 #endif 709 static __inline void 710 load_fs(u_short sel) 711 { 712 /* Preserve the fsbase value across the selector load */ 713 __asm __volatile("rdmsr; movw %0,%%fs; wrmsr" 714 : : "rm" (sel), "c" (MSR_FSBASE) : "eax", "edx"); 715 } 716 717 #ifndef MSR_GSBASE 718 #define MSR_GSBASE 0xc0000101 719 #endif 720 static __inline void 721 load_gs(u_short sel) 722 { 723 /* 724 * Preserve the gsbase value across the selector load. 725 * Note that we have to disable interrupts because the gsbase 726 * being trashed happens to be the kernel gsbase at the time. 727 */ 728 __asm __volatile("pushfq; cli; rdmsr; movw %0,%%gs; wrmsr; popfq" 729 : : "rm" (sel), "c" (MSR_GSBASE) : "eax", "edx"); 730 } 731 #else 732 /* Usable by userland */ 733 static __inline void 734 load_fs(u_short sel) 735 { 736 __asm __volatile("movw %0,%%fs" : : "rm" (sel)); 737 } 738 739 static __inline void 740 load_gs(u_short sel) 741 { 742 __asm __volatile("movw %0,%%gs" : : "rm" (sel)); 743 } 744 #endif 745 746 /* void lidt(struct region_descriptor *addr); */ 747 static __inline void 748 lidt(struct region_descriptor *addr) 749 { 750 __asm __volatile("lidt (%0)" : : "r" (addr)); 751 } 752 753 /* void lldt(u_short sel); */ 754 static __inline void 755 lldt(u_short sel) 756 { 757 __asm __volatile("lldt %0" : : "r" (sel)); 758 } 759 760 /* void ltr(u_short sel); */ 761 static __inline void 762 ltr(u_short sel) 763 { 764 __asm __volatile("ltr %0" : : "r" (sel)); 765 } 766 767 static __inline u_int64_t 768 rdr0(void) 769 { 770 u_int64_t data; 771 __asm __volatile("movq %%dr0,%0" : "=r" (data)); 772 return (data); 773 } 774 775 static __inline void 776 load_dr0(u_int64_t dr0) 777 { 778 __asm __volatile("movq %0,%%dr0" : : "r" (dr0)); 779 } 780 781 static __inline u_int64_t 782 rdr1(void) 783 { 784 u_int64_t data; 785 __asm __volatile("movq %%dr1,%0" : "=r" (data)); 786 return (data); 787 } 788 789 static __inline void 790 load_dr1(u_int64_t dr1) 791 { 792 __asm __volatile("movq %0,%%dr1" : : "r" (dr1)); 793 } 794 795 static __inline u_int64_t 796 rdr2(void) 797 { 798 u_int64_t data; 799 __asm __volatile("movq %%dr2,%0" : "=r" (data)); 800 return (data); 801 } 802 803 static __inline void 804 load_dr2(u_int64_t dr2) 805 { 806 __asm __volatile("movq %0,%%dr2" : : "r" (dr2)); 807 } 808 809 static __inline u_int64_t 810 rdr3(void) 811 { 812 u_int64_t data; 813 __asm __volatile("movq %%dr3,%0" : "=r" (data)); 814 return (data); 815 } 816 817 static __inline void 818 load_dr3(u_int64_t dr3) 819 { 820 __asm __volatile("movq %0,%%dr3" : : "r" (dr3)); 821 } 822 823 static __inline u_int64_t 824 rdr4(void) 825 { 826 u_int64_t data; 827 __asm __volatile("movq %%dr4,%0" : "=r" (data)); 828 return (data); 829 } 830 831 static __inline void 832 load_dr4(u_int64_t dr4) 833 { 834 __asm __volatile("movq %0,%%dr4" : : "r" (dr4)); 835 } 836 837 static __inline u_int64_t 838 rdr5(void) 839 { 840 u_int64_t data; 841 __asm __volatile("movq %%dr5,%0" : "=r" (data)); 842 return (data); 843 } 844 845 static __inline void 846 load_dr5(u_int64_t dr5) 847 { 848 __asm __volatile("movq %0,%%dr5" : : "r" (dr5)); 849 } 850 851 static __inline u_int64_t 852 rdr6(void) 853 { 854 u_int64_t data; 855 __asm __volatile("movq %%dr6,%0" : "=r" (data)); 856 return (data); 857 } 858 859 static __inline void 860 load_dr6(u_int64_t dr6) 861 { 862 __asm __volatile("movq %0,%%dr6" : : "r" (dr6)); 863 } 864 865 static __inline u_int64_t 866 rdr7(void) 867 { 868 u_int64_t data; 869 __asm __volatile("movq %%dr7,%0" : "=r" (data)); 870 return (data); 871 } 872 873 static __inline void 874 load_dr7(u_int64_t dr7) 875 { 876 __asm __volatile("movq %0,%%dr7" : : "r" (dr7)); 877 } 878 879 static __inline register_t 880 intr_disable(void) 881 { 882 register_t rflags; 883 884 rflags = read_rflags(); 885 cpu_disable_intr(); 886 return (rflags); 887 } 888 889 static __inline void 890 intr_restore(register_t rflags) 891 { 892 write_rflags(rflags); 893 } 894 895 #else /* !__GNUC__ */ 896 897 int breakpoint(void); 898 void cpu_pause(void); 899 u_int bsfl(u_int mask); 900 u_int bsrl(u_int mask); 901 void cpu_disable_intr(void); 902 void cpu_enable_intr(void); 903 void cpu_invlpg(u_long addr); 904 void cpu_invlpg_range(u_long start, u_long end); 905 void do_cpuid(u_int ax, u_int *p); 906 void halt(void); 907 u_char inb(u_int port); 908 u_int inl(u_int port); 909 void insb(u_int port, void *addr, size_t cnt); 910 void insl(u_int port, void *addr, size_t cnt); 911 void insw(u_int port, void *addr, size_t cnt); 912 void invd(void); 913 void invlpg(u_int addr); 914 void invlpg_range(u_int start, u_int end); 915 void cpu_invltlb(void); 916 u_short inw(u_int port); 917 void load_cr0(u_int cr0); 918 void load_cr3(u_int cr3); 919 void load_cr4(u_int cr4); 920 void load_fs(u_int sel); 921 void load_gs(u_int sel); 922 struct region_descriptor; 923 void lidt(struct region_descriptor *addr); 924 void lldt(u_short sel); 925 void ltr(u_short sel); 926 void outb(u_int port, u_char data); 927 void outl(u_int port, u_int data); 928 void outsb(u_int port, void *addr, size_t cnt); 929 void outsl(u_int port, void *addr, size_t cnt); 930 void outsw(u_int port, void *addr, size_t cnt); 931 void outw(u_int port, u_short data); 932 void ia32_pause(void); 933 u_int rcr0(void); 934 u_int rcr2(void); 935 u_int rcr3(void); 936 u_int rcr4(void); 937 u_short rfs(void); 938 u_short rgs(void); 939 u_int64_t rdmsr(u_int msr); 940 u_int64_t rdpmc(u_int pmc); 941 u_int64_t rdtsc(void); 942 u_int read_rflags(void); 943 void wbinvd(void); 944 void write_rflags(u_int rf); 945 void wrmsr(u_int msr, u_int64_t newval); 946 u_int64_t rdr0(void); 947 void load_dr0(u_int64_t dr0); 948 u_int64_t rdr1(void); 949 void load_dr1(u_int64_t dr1); 950 u_int64_t rdr2(void); 951 void load_dr2(u_int64_t dr2); 952 u_int64_t rdr3(void); 953 void load_dr3(u_int64_t dr3); 954 u_int64_t rdr4(void); 955 void load_dr4(u_int64_t dr4); 956 u_int64_t rdr5(void); 957 void load_dr5(u_int64_t dr5); 958 u_int64_t rdr6(void); 959 void load_dr6(u_int64_t dr6); 960 u_int64_t rdr7(void); 961 void load_dr7(u_int64_t dr7); 962 register_t intr_disable(void); 963 void intr_restore(register_t rf); 964 965 #endif /* __GNUC__ */ 966 967 int rdmsr_safe(u_int msr, uint64_t *val); 968 void reset_dbregs(void); 969 970 __END_DECLS 971 972 #endif /* !_CPU_CPUFUNC_H_ */ 973