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. Neither the name of the University nor the names of its contributors 16 * may be used to endorse or promote products derived from this software 17 * without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 * SUCH DAMAGE. 30 * 31 * $FreeBSD: src/sys/amd64/include/cpufunc.h,v 1.139 2004/01/28 23:53:04 peter Exp $ 32 */ 33 34 /* 35 * Functions to provide access to special i386 instructions. 36 * This in included in sys/systm.h, and that file should be 37 * used in preference to this. 38 */ 39 40 #ifndef _CPU_CPUFUNC_H_ 41 #define _CPU_CPUFUNC_H_ 42 43 #include <sys/cdefs.h> 44 #include <sys/thread.h> 45 #include <machine/psl.h> 46 #include <machine/smp.h> 47 48 struct thread; 49 struct region_descriptor; 50 struct pmap; 51 52 __BEGIN_DECLS 53 #define readb(va) (*(volatile u_int8_t *) (va)) 54 #define readw(va) (*(volatile u_int16_t *) (va)) 55 #define readl(va) (*(volatile u_int32_t *) (va)) 56 #define readq(va) (*(volatile u_int64_t *) (va)) 57 58 #define writeb(va, d) (*(volatile u_int8_t *) (va) = (d)) 59 #define writew(va, d) (*(volatile u_int16_t *) (va) = (d)) 60 #define writel(va, d) (*(volatile u_int32_t *) (va) = (d)) 61 #define writeq(va, d) (*(volatile u_int64_t *) (va) = (d)) 62 63 #ifdef __GNUC__ 64 65 #include <machine/lock.h> /* XXX */ 66 67 static __inline void 68 breakpoint(void) 69 { 70 __asm __volatile("int $3"); 71 } 72 73 static __inline void 74 cpu_pause(void) 75 { 76 __asm __volatile("pause":::"memory"); 77 } 78 79 static __inline u_int 80 bsfl(u_int mask) 81 { 82 u_int result; 83 84 __asm __volatile("bsfl %1,%0" : "=r" (result) : "rm" (mask)); 85 return (result); 86 } 87 88 static __inline u_long 89 bsfq(u_long mask) 90 { 91 u_long result; 92 93 __asm __volatile("bsfq %1,%0" : "=r" (result) : "rm" (mask)); 94 return (result); 95 } 96 97 static __inline u_long 98 bsflong(u_long mask) 99 { 100 u_long result; 101 102 __asm __volatile("bsfq %1,%0" : "=r" (result) : "rm" (mask)); 103 return (result); 104 } 105 106 static __inline u_int 107 bsrl(u_int mask) 108 { 109 u_int result; 110 111 __asm __volatile("bsrl %1,%0" : "=r" (result) : "rm" (mask)); 112 return (result); 113 } 114 115 static __inline u_long 116 bsrq(u_long mask) 117 { 118 u_long result; 119 120 __asm __volatile("bsrq %1,%0" : "=r" (result) : "rm" (mask)); 121 return (result); 122 } 123 124 static __inline void 125 clflush(u_long addr) 126 { 127 __asm __volatile("clflush %0" : : "m" (*(char *) addr)); 128 } 129 130 static __inline void 131 do_cpuid(u_int ax, u_int *p) 132 { 133 __asm __volatile("cpuid" 134 : "=a" (p[0]), "=b" (p[1]), "=c" (p[2]), "=d" (p[3]) 135 : "0" (ax)); 136 } 137 138 static __inline void 139 cpuid_count(u_int ax, u_int cx, u_int *p) 140 { 141 __asm __volatile("cpuid" 142 : "=a" (p[0]), "=b" (p[1]), "=c" (p[2]), "=d" (p[3]) 143 : "0" (ax), "c" (cx)); 144 } 145 146 #ifndef _CPU_DISABLE_INTR_DEFINED 147 148 static __inline void 149 cpu_disable_intr(void) 150 { 151 __asm __volatile("cli" : : : "memory"); 152 } 153 154 #endif 155 156 #ifndef _CPU_ENABLE_INTR_DEFINED 157 158 static __inline void 159 cpu_enable_intr(void) 160 { 161 __asm __volatile("sti"); 162 } 163 164 #endif 165 166 /* 167 * Cpu and compiler memory ordering fence. mfence ensures strong read and 168 * write ordering. 169 * 170 * A serializing or fence instruction is required here. A locked bus 171 * cycle on data for which we already own cache mastership is the most 172 * portable. 173 */ 174 static __inline void 175 cpu_mfence(void) 176 { 177 __asm __volatile("mfence" : : : "memory"); 178 } 179 180 /* 181 * cpu_lfence() ensures strong read ordering for reads issued prior 182 * to the instruction verses reads issued afterwords. 183 * 184 * A serializing or fence instruction is required here. A locked bus 185 * cycle on data for which we already own cache mastership is the most 186 * portable. 187 */ 188 static __inline void 189 cpu_lfence(void) 190 { 191 __asm __volatile("lfence" : : : "memory"); 192 } 193 194 /* 195 * cpu_sfence() ensures strong write ordering for writes issued prior 196 * to the instruction verses writes issued afterwords. Writes are 197 * ordered on intel cpus so we do not actually have to do anything. 198 */ 199 static __inline void 200 cpu_sfence(void) 201 { 202 /* 203 * NOTE: 204 * Don't use 'sfence' here, as it will create a lot of 205 * unnecessary stalls. 206 */ 207 __asm __volatile("" : : : "memory"); 208 } 209 210 /* 211 * cpu_ccfence() prevents the compiler from reordering instructions, in 212 * particular stores, relative to the current cpu. Use cpu_sfence() if 213 * you need to guarentee ordering by both the compiler and by the cpu. 214 * 215 * This also prevents the compiler from caching memory loads into local 216 * variables across the routine. 217 */ 218 static __inline void 219 cpu_ccfence(void) 220 { 221 __asm __volatile("" : : : "memory"); 222 } 223 224 /* 225 * This is a horrible, horrible hack that might have to be put at the 226 * end of certain procedures (on a case by case basis), just before it 227 * returns to avoid what we believe to be an unreported AMD cpu bug. 228 * Found to occur on both a Phenom II X4 820 (two of them), as well 229 * as a 48-core built around an Opteron 6168 (Id = 0x100f91 Stepping = 1). 230 * The problem does not appear to occur w/Intel cpus. 231 * 232 * The bug is likely related to either a write combining issue or the 233 * Return Address Stack (RAS) hardware cache. 234 * 235 * In particular, we had to do this for GCC's fill_sons_in_loop() routine 236 * which due to its deep recursion and stack flow appears to be able to 237 * tickle the amd cpu bug (w/ gcc-4.4.7). Adding a single 'nop' to the 238 * end of the routine just before it returns works around the bug. 239 * 240 * The bug appears to be extremely sensitive to %rip and %rsp values, to 241 * the point where even just inserting an instruction in an unrelated 242 * procedure (shifting the entire code base being run) effects the outcome. 243 * DragonFly is probably able to more readily reproduce the bug due to 244 * the stackgap randomization code. We would expect OpenBSD (where we got 245 * the stackgap randomization code from) to also be able to reproduce the 246 * issue. To date we have only reproduced the issue in DragonFly. 247 */ 248 #define __AMDCPUBUG_DFLY01_AVAILABLE__ 249 250 static __inline void 251 cpu_amdcpubug_dfly01(void) 252 { 253 __asm __volatile("nop" : : : "memory"); 254 } 255 256 #ifdef _KERNEL 257 258 #define HAVE_INLINE_FFS 259 260 static __inline int 261 ffs(int mask) 262 { 263 #if 0 264 /* 265 * Note that gcc-2's builtin ffs would be used if we didn't declare 266 * this inline or turn off the builtin. The builtin is faster but 267 * broken in gcc-2.4.5 and slower but working in gcc-2.5 and later 268 * versions. 269 */ 270 return (mask == 0 ? mask : (int)bsfl((u_int)mask) + 1); 271 #else 272 /* Actually, the above is way out of date. The builtins use cmov etc */ 273 return (__builtin_ffs(mask)); 274 #endif 275 } 276 277 #define HAVE_INLINE_FFSL 278 279 static __inline int 280 ffsl(long mask) 281 { 282 return (mask == 0 ? mask : (int)bsfq((u_long)mask) + 1); 283 } 284 285 #define HAVE_INLINE_FLS 286 287 static __inline int 288 fls(int mask) 289 { 290 return (mask == 0 ? mask : (int)bsrl((u_int)mask) + 1); 291 } 292 293 #define HAVE_INLINE_FLSL 294 295 static __inline int 296 flsl(long mask) 297 { 298 return (mask == 0 ? mask : (int)bsrq((u_long)mask) + 1); 299 } 300 301 #define HAVE_INLINE_FLSLL 302 303 static __inline int 304 flsll(long long mask) 305 { 306 return (flsl((long)mask)); 307 } 308 309 #endif /* _KERNEL */ 310 311 static __inline void 312 halt(void) 313 { 314 __asm __volatile("hlt"); 315 } 316 317 /* 318 * The following complications are to get around gcc not having a 319 * constraint letter for the range 0..255. We still put "d" in the 320 * constraint because "i" isn't a valid constraint when the port 321 * isn't constant. This only matters for -O0 because otherwise 322 * the non-working version gets optimized away. 323 * 324 * Use an expression-statement instead of a conditional expression 325 * because gcc-2.6.0 would promote the operands of the conditional 326 * and produce poor code for "if ((inb(var) & const1) == const2)". 327 * 328 * The unnecessary test `(port) < 0x10000' is to generate a warning if 329 * the `port' has type u_short or smaller. Such types are pessimal. 330 * This actually only works for signed types. The range check is 331 * careful to avoid generating warnings. 332 */ 333 #define inb(port) __extension__ ({ \ 334 u_char _data; \ 335 if (__builtin_constant_p(port) && ((port) & 0xffff) < 0x100 \ 336 && (port) < 0x10000) \ 337 _data = inbc(port); \ 338 else \ 339 _data = inbv(port); \ 340 _data; }) 341 342 #define outb(port, data) ( \ 343 __builtin_constant_p(port) && ((port) & 0xffff) < 0x100 \ 344 && (port) < 0x10000 \ 345 ? outbc(port, data) : outbv(port, data)) 346 347 static __inline u_char 348 inbc(u_int port) 349 { 350 u_char data; 351 352 __asm __volatile("inb %1,%0" : "=a" (data) : "id" ((u_short)(port))); 353 return (data); 354 } 355 356 static __inline void 357 outbc(u_int port, u_char data) 358 { 359 __asm __volatile("outb %0,%1" : : "a" (data), "id" ((u_short)(port))); 360 } 361 362 static __inline u_char 363 inbv(u_int port) 364 { 365 u_char data; 366 /* 367 * We use %%dx and not %1 here because i/o is done at %dx and not at 368 * %edx, while gcc generates inferior code (movw instead of movl) 369 * if we tell it to load (u_short) port. 370 */ 371 __asm __volatile("inb %%dx,%0" : "=a" (data) : "d" (port)); 372 return (data); 373 } 374 375 static __inline u_int 376 inl(u_int port) 377 { 378 u_int data; 379 380 __asm __volatile("inl %%dx,%0" : "=a" (data) : "d" (port)); 381 return (data); 382 } 383 384 static __inline void 385 insb(u_int port, void *addr, size_t cnt) 386 { 387 __asm __volatile("cld; rep; insb" 388 : "+D" (addr), "+c" (cnt) 389 : "d" (port) 390 : "memory"); 391 } 392 393 static __inline void 394 insw(u_int port, void *addr, size_t cnt) 395 { 396 __asm __volatile("cld; rep; insw" 397 : "+D" (addr), "+c" (cnt) 398 : "d" (port) 399 : "memory"); 400 } 401 402 static __inline void 403 insl(u_int port, void *addr, size_t cnt) 404 { 405 __asm __volatile("cld; rep; insl" 406 : "+D" (addr), "+c" (cnt) 407 : "d" (port) 408 : "memory"); 409 } 410 411 static __inline void 412 invd(void) 413 { 414 __asm __volatile("invd"); 415 } 416 417 #if defined(_KERNEL) 418 419 #ifndef _CPU_INVLPG_DEFINED 420 421 /* 422 * Invalidate a particular VA on this cpu only 423 * 424 * TLB flush for an individual page (even if it has PG_G). 425 * Only works on 486+ CPUs (i386 does not have PG_G). 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 #ifdef _KERNEL 562 #include <machine/cputypes.h> 563 #include <machine/md_var.h> 564 565 static __inline u_int64_t 566 rdtsc_ordered(void) 567 { 568 if (cpu_vendor_id == CPU_VENDOR_INTEL) 569 cpu_lfence(); 570 else 571 cpu_mfence(); 572 return rdtsc(); 573 } 574 #endif 575 576 static __inline void 577 wbinvd(void) 578 { 579 __asm __volatile("wbinvd"); 580 } 581 582 #if defined(_KERNEL) 583 void cpu_wbinvd_on_all_cpus_callback(void *arg); 584 585 static __inline void 586 cpu_wbinvd_on_all_cpus(void) 587 { 588 lwkt_cpusync_simple(smp_active_mask, cpu_wbinvd_on_all_cpus_callback, NULL); 589 } 590 #endif 591 592 static __inline void 593 write_rflags(u_long rf) 594 { 595 __asm __volatile("pushq %0; popfq" : : "r" (rf)); 596 } 597 598 static __inline void 599 wrmsr(u_int msr, u_int64_t newval) 600 { 601 u_int32_t low, high; 602 603 low = newval; 604 high = newval >> 32; 605 __asm __volatile("wrmsr" : : "a" (low), "d" (high), "c" (msr)); 606 } 607 608 static __inline void 609 xsetbv(u_int ecx, u_int eax, u_int edx) 610 { 611 __asm __volatile(".byte 0x0f,0x01,0xd1" 612 : 613 : "a" (eax), "c" (ecx), "d" (edx)); 614 } 615 616 static __inline void 617 load_cr0(u_long data) 618 { 619 620 __asm __volatile("movq %0,%%cr0" : : "r" (data)); 621 } 622 623 static __inline u_long 624 rcr0(void) 625 { 626 u_long data; 627 628 __asm __volatile("movq %%cr0,%0" : "=r" (data)); 629 return (data); 630 } 631 632 static __inline u_long 633 rcr2(void) 634 { 635 u_long data; 636 637 __asm __volatile("movq %%cr2,%0" : "=r" (data)); 638 return (data); 639 } 640 641 static __inline void 642 load_cr3(u_long data) 643 { 644 645 __asm __volatile("movq %0,%%cr3" : : "r" (data) : "memory"); 646 } 647 648 static __inline u_long 649 rcr3(void) 650 { 651 u_long data; 652 653 __asm __volatile("movq %%cr3,%0" : "=r" (data)); 654 return (data); 655 } 656 657 static __inline void 658 load_cr4(u_long data) 659 { 660 __asm __volatile("movq %0,%%cr4" : : "r" (data)); 661 } 662 663 static __inline u_long 664 rcr4(void) 665 { 666 u_long data; 667 668 __asm __volatile("movq %%cr4,%0" : "=r" (data)); 669 return (data); 670 } 671 672 #ifndef _CPU_INVLTLB_DEFINED 673 674 /* 675 * Invalidate the TLB on this cpu only 676 */ 677 static __inline void 678 cpu_invltlb(void) 679 { 680 load_cr3(rcr3()); 681 #if defined(SWTCH_OPTIM_STATS) 682 ++tlb_flush_count; 683 #endif 684 } 685 686 #endif 687 688 extern void smp_invltlb(void); 689 extern void smp_sniff(void); 690 extern void cpu_sniff(int dcpu); 691 692 static __inline u_short 693 rfs(void) 694 { 695 u_short sel; 696 __asm __volatile("movw %%fs,%0" : "=rm" (sel)); 697 return (sel); 698 } 699 700 static __inline u_short 701 rgs(void) 702 { 703 u_short sel; 704 __asm __volatile("movw %%gs,%0" : "=rm" (sel)); 705 return (sel); 706 } 707 708 static __inline void 709 load_ds(u_short sel) 710 { 711 __asm __volatile("movw %0,%%ds" : : "rm" (sel)); 712 } 713 714 static __inline void 715 load_es(u_short sel) 716 { 717 __asm __volatile("movw %0,%%es" : : "rm" (sel)); 718 } 719 720 #ifdef _KERNEL 721 /* This is defined in <machine/specialreg.h> but is too painful to get to */ 722 #ifndef MSR_FSBASE 723 #define MSR_FSBASE 0xc0000100 724 #endif 725 static __inline void 726 load_fs(u_short sel) 727 { 728 /* Preserve the fsbase value across the selector load */ 729 __asm __volatile("rdmsr; movw %0,%%fs; wrmsr" 730 : : "rm" (sel), "c" (MSR_FSBASE) : "eax", "edx"); 731 } 732 733 #ifndef MSR_GSBASE 734 #define MSR_GSBASE 0xc0000101 735 #endif 736 static __inline void 737 load_gs(u_short sel) 738 { 739 /* 740 * Preserve the gsbase value across the selector load. 741 * Note that we have to disable interrupts because the gsbase 742 * being trashed happens to be the kernel gsbase at the time. 743 */ 744 __asm __volatile("pushfq; cli; rdmsr; movw %0,%%gs; wrmsr; popfq" 745 : : "rm" (sel), "c" (MSR_GSBASE) : "eax", "edx"); 746 } 747 #else 748 /* Usable by userland */ 749 static __inline void 750 load_fs(u_short sel) 751 { 752 __asm __volatile("movw %0,%%fs" : : "rm" (sel)); 753 } 754 755 static __inline void 756 load_gs(u_short sel) 757 { 758 __asm __volatile("movw %0,%%gs" : : "rm" (sel)); 759 } 760 #endif 761 762 /* void lidt(struct region_descriptor *addr); */ 763 static __inline void 764 lidt(struct region_descriptor *addr) 765 { 766 __asm __volatile("lidt (%0)" : : "r" (addr)); 767 } 768 769 /* void lldt(u_short sel); */ 770 static __inline void 771 lldt(u_short sel) 772 { 773 __asm __volatile("lldt %0" : : "r" (sel)); 774 } 775 776 /* void ltr(u_short sel); */ 777 static __inline void 778 ltr(u_short sel) 779 { 780 __asm __volatile("ltr %0" : : "r" (sel)); 781 } 782 783 static __inline u_int64_t 784 rdr0(void) 785 { 786 u_int64_t data; 787 __asm __volatile("movq %%dr0,%0" : "=r" (data)); 788 return (data); 789 } 790 791 static __inline void 792 load_dr0(u_int64_t dr0) 793 { 794 __asm __volatile("movq %0,%%dr0" : : "r" (dr0)); 795 } 796 797 static __inline u_int64_t 798 rdr1(void) 799 { 800 u_int64_t data; 801 __asm __volatile("movq %%dr1,%0" : "=r" (data)); 802 return (data); 803 } 804 805 static __inline void 806 load_dr1(u_int64_t dr1) 807 { 808 __asm __volatile("movq %0,%%dr1" : : "r" (dr1)); 809 } 810 811 static __inline u_int64_t 812 rdr2(void) 813 { 814 u_int64_t data; 815 __asm __volatile("movq %%dr2,%0" : "=r" (data)); 816 return (data); 817 } 818 819 static __inline void 820 load_dr2(u_int64_t dr2) 821 { 822 __asm __volatile("movq %0,%%dr2" : : "r" (dr2)); 823 } 824 825 static __inline u_int64_t 826 rdr3(void) 827 { 828 u_int64_t data; 829 __asm __volatile("movq %%dr3,%0" : "=r" (data)); 830 return (data); 831 } 832 833 static __inline void 834 load_dr3(u_int64_t dr3) 835 { 836 __asm __volatile("movq %0,%%dr3" : : "r" (dr3)); 837 } 838 839 static __inline u_int64_t 840 rdr4(void) 841 { 842 u_int64_t data; 843 __asm __volatile("movq %%dr4,%0" : "=r" (data)); 844 return (data); 845 } 846 847 static __inline void 848 load_dr4(u_int64_t dr4) 849 { 850 __asm __volatile("movq %0,%%dr4" : : "r" (dr4)); 851 } 852 853 static __inline u_int64_t 854 rdr5(void) 855 { 856 u_int64_t data; 857 __asm __volatile("movq %%dr5,%0" : "=r" (data)); 858 return (data); 859 } 860 861 static __inline void 862 load_dr5(u_int64_t dr5) 863 { 864 __asm __volatile("movq %0,%%dr5" : : "r" (dr5)); 865 } 866 867 static __inline u_int64_t 868 rdr6(void) 869 { 870 u_int64_t data; 871 __asm __volatile("movq %%dr6,%0" : "=r" (data)); 872 return (data); 873 } 874 875 static __inline void 876 load_dr6(u_int64_t dr6) 877 { 878 __asm __volatile("movq %0,%%dr6" : : "r" (dr6)); 879 } 880 881 static __inline u_int64_t 882 rdr7(void) 883 { 884 u_int64_t data; 885 __asm __volatile("movq %%dr7,%0" : "=r" (data)); 886 return (data); 887 } 888 889 static __inline void 890 load_dr7(u_int64_t dr7) 891 { 892 __asm __volatile("movq %0,%%dr7" : : "r" (dr7)); 893 } 894 895 static __inline register_t 896 intr_disable(void) 897 { 898 register_t rflags; 899 900 rflags = read_rflags(); 901 cpu_disable_intr(); 902 return (rflags); 903 } 904 905 static __inline void 906 intr_restore(register_t rflags) 907 { 908 write_rflags(rflags); 909 } 910 911 #else /* !__GNUC__ */ 912 913 int breakpoint(void); 914 void cpu_pause(void); 915 u_int bsfl(u_int mask); 916 u_int bsrl(u_int mask); 917 void cpu_disable_intr(void); 918 void cpu_enable_intr(void); 919 void cpu_invlpg(u_long addr); 920 void cpu_invlpg_range(u_long start, u_long end); 921 void do_cpuid(u_int ax, u_int *p); 922 void halt(void); 923 u_char inb(u_int port); 924 u_int inl(u_int port); 925 void insb(u_int port, void *addr, size_t cnt); 926 void insl(u_int port, void *addr, size_t cnt); 927 void insw(u_int port, void *addr, size_t cnt); 928 void invd(void); 929 void invlpg_range(u_int start, u_int end); 930 void cpu_invltlb(void); 931 u_short inw(u_int port); 932 void load_cr0(u_int cr0); 933 void load_cr3(u_int cr3); 934 void load_cr4(u_int cr4); 935 void load_fs(u_int sel); 936 void load_gs(u_int sel); 937 struct region_descriptor; 938 void lidt(struct region_descriptor *addr); 939 void lldt(u_short sel); 940 void ltr(u_short sel); 941 void outb(u_int port, u_char data); 942 void outl(u_int port, u_int data); 943 void outsb(u_int port, void *addr, size_t cnt); 944 void outsl(u_int port, void *addr, size_t cnt); 945 void outsw(u_int port, void *addr, size_t cnt); 946 void outw(u_int port, u_short data); 947 void ia32_pause(void); 948 u_int rcr0(void); 949 u_int rcr2(void); 950 u_int rcr3(void); 951 u_int rcr4(void); 952 u_short rfs(void); 953 u_short rgs(void); 954 u_int64_t rdmsr(u_int msr); 955 u_int64_t rdpmc(u_int pmc); 956 u_int64_t rdtsc(void); 957 u_int read_rflags(void); 958 void wbinvd(void); 959 void write_rflags(u_int rf); 960 void wrmsr(u_int msr, u_int64_t newval); 961 u_int64_t rdr0(void); 962 void load_dr0(u_int64_t dr0); 963 u_int64_t rdr1(void); 964 void load_dr1(u_int64_t dr1); 965 u_int64_t rdr2(void); 966 void load_dr2(u_int64_t dr2); 967 u_int64_t rdr3(void); 968 void load_dr3(u_int64_t dr3); 969 u_int64_t rdr4(void); 970 void load_dr4(u_int64_t dr4); 971 u_int64_t rdr5(void); 972 void load_dr5(u_int64_t dr5); 973 u_int64_t rdr6(void); 974 void load_dr6(u_int64_t dr6); 975 u_int64_t rdr7(void); 976 void load_dr7(u_int64_t dr7); 977 register_t intr_disable(void); 978 void intr_restore(register_t rf); 979 980 #endif /* __GNUC__ */ 981 982 int rdmsr_safe(u_int msr, uint64_t *val); 983 int wrmsr_safe(u_int msr, uint64_t newval); 984 void reset_dbregs(void); 985 986 __END_DECLS 987 988 #endif /* !_CPU_CPUFUNC_H_ */ 989