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":::"memory"); 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 void smp_invltlb(void); 415 void smp_invltlb_intr(void); 416 417 #ifndef _CPU_INVLPG_DEFINED 418 419 /* 420 * Invalidate a particular VA on this cpu only 421 * 422 * TLB flush for an individual page (even if it has PG_G). 423 * Only works on 486+ CPUs (i386 does not have PG_G). 424 */ 425 static __inline void 426 cpu_invlpg(void *addr) 427 { 428 __asm __volatile("invlpg %0" : : "m" (*(char *)addr) : "memory"); 429 } 430 431 #endif 432 433 #if defined(_KERNEL) 434 struct smp_invlpg_range_cpusync_arg { 435 vm_offset_t sva; 436 vm_offset_t eva; 437 }; 438 439 void 440 smp_invlpg_range_cpusync(void *arg); 441 442 static __inline void 443 smp_invlpg_range(cpumask_t mask, vm_offset_t sva, vm_offset_t eva) 444 { 445 struct smp_invlpg_range_cpusync_arg arg; 446 447 arg.sva = sva; 448 arg.eva = eva; 449 lwkt_cpusync_simple(mask, smp_invlpg_range_cpusync, &arg); 450 } 451 #endif 452 453 static __inline void 454 cpu_nop(void) 455 { 456 __asm __volatile("rep; nop"); 457 } 458 459 #endif /* _KERNEL */ 460 461 static __inline u_short 462 inw(u_int port) 463 { 464 u_short data; 465 466 __asm __volatile("inw %%dx,%0" : "=a" (data) : "d" (port)); 467 return (data); 468 } 469 470 static __inline u_int 471 loadandclear(volatile u_int *addr) 472 { 473 u_int result; 474 475 __asm __volatile("xorl %0,%0; xchgl %1,%0" 476 : "=&r" (result) : "m" (*addr)); 477 return (result); 478 } 479 480 static __inline void 481 outbv(u_int port, u_char data) 482 { 483 u_char al; 484 /* 485 * Use an unnecessary assignment to help gcc's register allocator. 486 * This make a large difference for gcc-1.40 and a tiny difference 487 * for gcc-2.6.0. For gcc-1.40, al had to be ``asm("ax")'' for 488 * best results. gcc-2.6.0 can't handle this. 489 */ 490 al = data; 491 __asm __volatile("outb %0,%%dx" : : "a" (al), "d" (port)); 492 } 493 494 static __inline void 495 outl(u_int port, u_int data) 496 { 497 /* 498 * outl() and outw() aren't used much so we haven't looked at 499 * possible micro-optimizations such as the unnecessary 500 * assignment for them. 501 */ 502 __asm __volatile("outl %0,%%dx" : : "a" (data), "d" (port)); 503 } 504 505 static __inline void 506 outsb(u_int port, const void *addr, size_t cnt) 507 { 508 __asm __volatile("cld; rep; outsb" 509 : "+S" (addr), "+c" (cnt) 510 : "d" (port)); 511 } 512 513 static __inline void 514 outsw(u_int port, const void *addr, size_t cnt) 515 { 516 __asm __volatile("cld; rep; outsw" 517 : "+S" (addr), "+c" (cnt) 518 : "d" (port)); 519 } 520 521 static __inline void 522 outsl(u_int port, const void *addr, size_t cnt) 523 { 524 __asm __volatile("cld; rep; outsl" 525 : "+S" (addr), "+c" (cnt) 526 : "d" (port)); 527 } 528 529 static __inline void 530 outw(u_int port, u_short data) 531 { 532 __asm __volatile("outw %0,%%dx" : : "a" (data), "d" (port)); 533 } 534 535 static __inline void 536 ia32_pause(void) 537 { 538 __asm __volatile("pause"); 539 } 540 541 static __inline u_long 542 read_rflags(void) 543 { 544 u_long rf; 545 546 __asm __volatile("pushfq; popq %0" : "=r" (rf)); 547 return (rf); 548 } 549 550 static __inline u_int64_t 551 rdmsr(u_int msr) 552 { 553 u_int32_t low, high; 554 555 __asm __volatile("rdmsr" : "=a" (low), "=d" (high) : "c" (msr)); 556 return (low | ((u_int64_t)high << 32)); 557 } 558 559 static __inline u_int64_t 560 rdpmc(u_int pmc) 561 { 562 u_int32_t low, high; 563 564 __asm __volatile("rdpmc" : "=a" (low), "=d" (high) : "c" (pmc)); 565 return (low | ((u_int64_t)high << 32)); 566 } 567 568 #define _RDTSC_SUPPORTED_ 569 570 static __inline u_int64_t 571 rdtsc(void) 572 { 573 u_int32_t low, high; 574 575 __asm __volatile("rdtsc" : "=a" (low), "=d" (high)); 576 return (low | ((u_int64_t)high << 32)); 577 } 578 579 #ifdef _KERNEL 580 #include <machine/cputypes.h> 581 #include <machine/md_var.h> 582 583 static __inline u_int64_t 584 rdtsc_ordered(void) 585 { 586 if (cpu_vendor_id == CPU_VENDOR_INTEL) 587 cpu_lfence(); 588 else 589 cpu_mfence(); 590 return rdtsc(); 591 } 592 #endif 593 594 static __inline void 595 wbinvd(void) 596 { 597 __asm __volatile("wbinvd"); 598 } 599 600 #if defined(_KERNEL) 601 void cpu_wbinvd_on_all_cpus_callback(void *arg); 602 603 static __inline void 604 cpu_wbinvd_on_all_cpus(void) 605 { 606 lwkt_cpusync_simple(smp_active_mask, cpu_wbinvd_on_all_cpus_callback, NULL); 607 } 608 #endif 609 610 static __inline void 611 write_rflags(u_long rf) 612 { 613 __asm __volatile("pushq %0; popfq" : : "r" (rf)); 614 } 615 616 static __inline void 617 wrmsr(u_int msr, u_int64_t newval) 618 { 619 u_int32_t low, high; 620 621 low = newval; 622 high = newval >> 32; 623 __asm __volatile("wrmsr" : : "a" (low), "d" (high), "c" (msr)); 624 } 625 626 static __inline void 627 xsetbv(u_int ecx, u_int eax, u_int edx) 628 { 629 __asm __volatile(".byte 0x0f,0x01,0xd1" 630 : 631 : "a" (eax), "c" (ecx), "d" (edx)); 632 } 633 634 static __inline void 635 load_cr0(u_long data) 636 { 637 638 __asm __volatile("movq %0,%%cr0" : : "r" (data)); 639 } 640 641 static __inline u_long 642 rcr0(void) 643 { 644 u_long data; 645 646 __asm __volatile("movq %%cr0,%0" : "=r" (data)); 647 return (data); 648 } 649 650 static __inline u_long 651 rcr2(void) 652 { 653 u_long data; 654 655 __asm __volatile("movq %%cr2,%0" : "=r" (data)); 656 return (data); 657 } 658 659 static __inline void 660 load_cr3(u_long data) 661 { 662 663 __asm __volatile("movq %0,%%cr3" : : "r" (data) : "memory"); 664 } 665 666 static __inline u_long 667 rcr3(void) 668 { 669 u_long data; 670 671 __asm __volatile("movq %%cr3,%0" : "=r" (data)); 672 return (data); 673 } 674 675 static __inline void 676 load_cr4(u_long data) 677 { 678 __asm __volatile("movq %0,%%cr4" : : "r" (data)); 679 } 680 681 static __inline u_long 682 rcr4(void) 683 { 684 u_long data; 685 686 __asm __volatile("movq %%cr4,%0" : "=r" (data)); 687 return (data); 688 } 689 690 #ifndef _CPU_INVLTLB_DEFINED 691 692 /* 693 * Invalidate the TLB on this cpu only 694 */ 695 static __inline void 696 cpu_invltlb(void) 697 { 698 load_cr3(rcr3()); 699 #if defined(SWTCH_OPTIM_STATS) 700 ++tlb_flush_count; 701 #endif 702 } 703 704 #endif 705 706 static __inline u_short 707 rfs(void) 708 { 709 u_short sel; 710 __asm __volatile("movw %%fs,%0" : "=rm" (sel)); 711 return (sel); 712 } 713 714 static __inline u_short 715 rgs(void) 716 { 717 u_short sel; 718 __asm __volatile("movw %%gs,%0" : "=rm" (sel)); 719 return (sel); 720 } 721 722 static __inline void 723 load_ds(u_short sel) 724 { 725 __asm __volatile("movw %0,%%ds" : : "rm" (sel)); 726 } 727 728 static __inline void 729 load_es(u_short sel) 730 { 731 __asm __volatile("movw %0,%%es" : : "rm" (sel)); 732 } 733 734 #ifdef _KERNEL 735 /* This is defined in <machine/specialreg.h> but is too painful to get to */ 736 #ifndef MSR_FSBASE 737 #define MSR_FSBASE 0xc0000100 738 #endif 739 static __inline void 740 load_fs(u_short sel) 741 { 742 /* Preserve the fsbase value across the selector load */ 743 __asm __volatile("rdmsr; movw %0,%%fs; wrmsr" 744 : : "rm" (sel), "c" (MSR_FSBASE) : "eax", "edx"); 745 } 746 747 #ifndef MSR_GSBASE 748 #define MSR_GSBASE 0xc0000101 749 #endif 750 static __inline void 751 load_gs(u_short sel) 752 { 753 /* 754 * Preserve the gsbase value across the selector load. 755 * Note that we have to disable interrupts because the gsbase 756 * being trashed happens to be the kernel gsbase at the time. 757 */ 758 __asm __volatile("pushfq; cli; rdmsr; movw %0,%%gs; wrmsr; popfq" 759 : : "rm" (sel), "c" (MSR_GSBASE) : "eax", "edx"); 760 } 761 #else 762 /* Usable by userland */ 763 static __inline void 764 load_fs(u_short sel) 765 { 766 __asm __volatile("movw %0,%%fs" : : "rm" (sel)); 767 } 768 769 static __inline void 770 load_gs(u_short sel) 771 { 772 __asm __volatile("movw %0,%%gs" : : "rm" (sel)); 773 } 774 #endif 775 776 /* void lidt(struct region_descriptor *addr); */ 777 static __inline void 778 lidt(struct region_descriptor *addr) 779 { 780 __asm __volatile("lidt (%0)" : : "r" (addr)); 781 } 782 783 /* void lldt(u_short sel); */ 784 static __inline void 785 lldt(u_short sel) 786 { 787 __asm __volatile("lldt %0" : : "r" (sel)); 788 } 789 790 /* void ltr(u_short sel); */ 791 static __inline void 792 ltr(u_short sel) 793 { 794 __asm __volatile("ltr %0" : : "r" (sel)); 795 } 796 797 static __inline u_int64_t 798 rdr0(void) 799 { 800 u_int64_t data; 801 __asm __volatile("movq %%dr0,%0" : "=r" (data)); 802 return (data); 803 } 804 805 static __inline void 806 load_dr0(u_int64_t dr0) 807 { 808 __asm __volatile("movq %0,%%dr0" : : "r" (dr0)); 809 } 810 811 static __inline u_int64_t 812 rdr1(void) 813 { 814 u_int64_t data; 815 __asm __volatile("movq %%dr1,%0" : "=r" (data)); 816 return (data); 817 } 818 819 static __inline void 820 load_dr1(u_int64_t dr1) 821 { 822 __asm __volatile("movq %0,%%dr1" : : "r" (dr1)); 823 } 824 825 static __inline u_int64_t 826 rdr2(void) 827 { 828 u_int64_t data; 829 __asm __volatile("movq %%dr2,%0" : "=r" (data)); 830 return (data); 831 } 832 833 static __inline void 834 load_dr2(u_int64_t dr2) 835 { 836 __asm __volatile("movq %0,%%dr2" : : "r" (dr2)); 837 } 838 839 static __inline u_int64_t 840 rdr3(void) 841 { 842 u_int64_t data; 843 __asm __volatile("movq %%dr3,%0" : "=r" (data)); 844 return (data); 845 } 846 847 static __inline void 848 load_dr3(u_int64_t dr3) 849 { 850 __asm __volatile("movq %0,%%dr3" : : "r" (dr3)); 851 } 852 853 static __inline u_int64_t 854 rdr4(void) 855 { 856 u_int64_t data; 857 __asm __volatile("movq %%dr4,%0" : "=r" (data)); 858 return (data); 859 } 860 861 static __inline void 862 load_dr4(u_int64_t dr4) 863 { 864 __asm __volatile("movq %0,%%dr4" : : "r" (dr4)); 865 } 866 867 static __inline u_int64_t 868 rdr5(void) 869 { 870 u_int64_t data; 871 __asm __volatile("movq %%dr5,%0" : "=r" (data)); 872 return (data); 873 } 874 875 static __inline void 876 load_dr5(u_int64_t dr5) 877 { 878 __asm __volatile("movq %0,%%dr5" : : "r" (dr5)); 879 } 880 881 static __inline u_int64_t 882 rdr6(void) 883 { 884 u_int64_t data; 885 __asm __volatile("movq %%dr6,%0" : "=r" (data)); 886 return (data); 887 } 888 889 static __inline void 890 load_dr6(u_int64_t dr6) 891 { 892 __asm __volatile("movq %0,%%dr6" : : "r" (dr6)); 893 } 894 895 static __inline u_int64_t 896 rdr7(void) 897 { 898 u_int64_t data; 899 __asm __volatile("movq %%dr7,%0" : "=r" (data)); 900 return (data); 901 } 902 903 static __inline void 904 load_dr7(u_int64_t dr7) 905 { 906 __asm __volatile("movq %0,%%dr7" : : "r" (dr7)); 907 } 908 909 static __inline register_t 910 intr_disable(void) 911 { 912 register_t rflags; 913 914 rflags = read_rflags(); 915 cpu_disable_intr(); 916 return (rflags); 917 } 918 919 static __inline void 920 intr_restore(register_t rflags) 921 { 922 write_rflags(rflags); 923 } 924 925 #else /* !__GNUC__ */ 926 927 int breakpoint(void); 928 void cpu_pause(void); 929 u_int bsfl(u_int mask); 930 u_int bsrl(u_int mask); 931 void cpu_disable_intr(void); 932 void cpu_enable_intr(void); 933 void cpu_invlpg(u_long addr); 934 void cpu_invlpg_range(u_long start, u_long end); 935 void do_cpuid(u_int ax, u_int *p); 936 void halt(void); 937 u_char inb(u_int port); 938 u_int inl(u_int port); 939 void insb(u_int port, void *addr, size_t cnt); 940 void insl(u_int port, void *addr, size_t cnt); 941 void insw(u_int port, void *addr, size_t cnt); 942 void invd(void); 943 void invlpg_range(u_int start, u_int end); 944 void cpu_invltlb(void); 945 u_short inw(u_int port); 946 void load_cr0(u_int cr0); 947 void load_cr3(u_int cr3); 948 void load_cr4(u_int cr4); 949 void load_fs(u_int sel); 950 void load_gs(u_int sel); 951 struct region_descriptor; 952 void lidt(struct region_descriptor *addr); 953 void lldt(u_short sel); 954 void ltr(u_short sel); 955 void outb(u_int port, u_char data); 956 void outl(u_int port, u_int data); 957 void outsb(u_int port, void *addr, size_t cnt); 958 void outsl(u_int port, void *addr, size_t cnt); 959 void outsw(u_int port, void *addr, size_t cnt); 960 void outw(u_int port, u_short data); 961 void ia32_pause(void); 962 u_int rcr0(void); 963 u_int rcr2(void); 964 u_int rcr3(void); 965 u_int rcr4(void); 966 u_short rfs(void); 967 u_short rgs(void); 968 u_int64_t rdmsr(u_int msr); 969 u_int64_t rdpmc(u_int pmc); 970 u_int64_t rdtsc(void); 971 u_int read_rflags(void); 972 void wbinvd(void); 973 void write_rflags(u_int rf); 974 void wrmsr(u_int msr, u_int64_t newval); 975 u_int64_t rdr0(void); 976 void load_dr0(u_int64_t dr0); 977 u_int64_t rdr1(void); 978 void load_dr1(u_int64_t dr1); 979 u_int64_t rdr2(void); 980 void load_dr2(u_int64_t dr2); 981 u_int64_t rdr3(void); 982 void load_dr3(u_int64_t dr3); 983 u_int64_t rdr4(void); 984 void load_dr4(u_int64_t dr4); 985 u_int64_t rdr5(void); 986 void load_dr5(u_int64_t dr5); 987 u_int64_t rdr6(void); 988 void load_dr6(u_int64_t dr6); 989 u_int64_t rdr7(void); 990 void load_dr7(u_int64_t dr7); 991 register_t intr_disable(void); 992 void intr_restore(register_t rf); 993 994 #endif /* __GNUC__ */ 995 996 int rdmsr_safe(u_int msr, uint64_t *val); 997 int wrmsr_safe(u_int msr, uint64_t newval); 998 void reset_dbregs(void); 999 1000 __END_DECLS 1001 1002 #endif /* !_CPU_CPUFUNC_H_ */ 1003