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