cpufunc.h revision 220629
1/*- 2 * Copyright (c) 1993 The Regents of the University of California. 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 4. Neither the name of the University nor the names of its contributors 14 * may be used to endorse or promote products derived from this software 15 * without specific prior written permission. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27 * SUCH DAMAGE. 28 * 29 * $FreeBSD: head/sys/i386/include/cpufunc.h 220629 2011-04-14 16:19:41Z jkim $ 30 */ 31 32/* 33 * Functions to provide access to special i386 instructions. 34 * This in included in sys/systm.h, and that file should be 35 * used in preference to this. 36 */ 37 38#ifndef _MACHINE_CPUFUNC_H_ 39#define _MACHINE_CPUFUNC_H_ 40 41#ifndef _SYS_CDEFS_H_ 42#error this file needs sys/cdefs.h as a prerequisite 43#endif 44 45#ifdef XEN 46extern void xen_cli(void); 47extern void xen_sti(void); 48extern u_int xen_rcr2(void); 49extern void xen_load_cr3(u_int data); 50extern void xen_tlb_flush(void); 51extern void xen_invlpg(u_int addr); 52extern void write_eflags(u_int eflags); 53extern u_int read_eflags(void); 54#endif 55 56struct region_descriptor; 57 58#define readb(va) (*(volatile uint8_t *) (va)) 59#define readw(va) (*(volatile uint16_t *) (va)) 60#define readl(va) (*(volatile uint32_t *) (va)) 61 62#define writeb(va, d) (*(volatile uint8_t *) (va) = (d)) 63#define writew(va, d) (*(volatile uint16_t *) (va) = (d)) 64#define writel(va, d) (*(volatile uint32_t *) (va) = (d)) 65 66#if defined(__GNUCLIKE_ASM) && defined(__CC_SUPPORTS___INLINE) 67 68static __inline void 69breakpoint(void) 70{ 71 __asm __volatile("int $3"); 72} 73 74static __inline u_int 75bsfl(u_int mask) 76{ 77 u_int result; 78 79 __asm("bsfl %1,%0" : "=r" (result) : "rm" (mask) : "cc"); 80 return (result); 81} 82 83static __inline u_int 84bsrl(u_int mask) 85{ 86 u_int result; 87 88 __asm("bsrl %1,%0" : "=r" (result) : "rm" (mask) : "cc"); 89 return (result); 90} 91 92static __inline void 93clflush(u_long addr) 94{ 95 96 __asm __volatile("clflush %0" : : "m" (*(char *)addr)); 97} 98 99static __inline void 100disable_intr(void) 101{ 102#ifdef XEN 103 xen_cli(); 104#else 105 __asm __volatile("cli" : : : "memory"); 106#endif 107} 108 109static __inline void 110do_cpuid(u_int ax, u_int *p) 111{ 112 __asm __volatile("cpuid" 113 : "=a" (p[0]), "=b" (p[1]), "=c" (p[2]), "=d" (p[3]) 114 : "0" (ax)); 115} 116 117static __inline void 118cpuid_count(u_int ax, u_int cx, u_int *p) 119{ 120 __asm __volatile("cpuid" 121 : "=a" (p[0]), "=b" (p[1]), "=c" (p[2]), "=d" (p[3]) 122 : "0" (ax), "c" (cx)); 123} 124 125static __inline void 126enable_intr(void) 127{ 128#ifdef XEN 129 xen_sti(); 130#else 131 __asm __volatile("sti"); 132#endif 133} 134 135static __inline void 136cpu_monitor(const void *addr, int extensions, int hints) 137{ 138 __asm __volatile("monitor;" 139 : :"a" (addr), "c" (extensions), "d"(hints)); 140} 141 142static __inline void 143cpu_mwait(int extensions, int hints) 144{ 145 __asm __volatile("mwait;" : :"a" (hints), "c" (extensions)); 146} 147 148static __inline void 149mfence(void) 150{ 151 152 __asm __volatile("mfence" : : : "memory"); 153} 154 155#ifdef _KERNEL 156 157#define HAVE_INLINE_FFS 158 159static __inline int 160ffs(int mask) 161{ 162 /* 163 * Note that gcc-2's builtin ffs would be used if we didn't declare 164 * this inline or turn off the builtin. The builtin is faster but 165 * broken in gcc-2.4.5 and slower but working in gcc-2.5 and later 166 * versions. 167 */ 168 return (mask == 0 ? mask : (int)bsfl((u_int)mask) + 1); 169} 170 171#define HAVE_INLINE_FLS 172 173static __inline int 174fls(int mask) 175{ 176 return (mask == 0 ? mask : (int)bsrl((u_int)mask) + 1); 177} 178 179#endif /* _KERNEL */ 180 181static __inline void 182halt(void) 183{ 184 __asm __volatile("hlt"); 185} 186 187static __inline u_char 188inb(u_int port) 189{ 190 u_char data; 191 192 __asm __volatile("inb %w1, %0" : "=a" (data) : "Nd" (port)); 193 return (data); 194} 195 196static __inline u_int 197inl(u_int port) 198{ 199 u_int data; 200 201 __asm __volatile("inl %w1, %0" : "=a" (data) : "Nd" (port)); 202 return (data); 203} 204 205static __inline void 206insb(u_int port, void *addr, size_t count) 207{ 208 __asm __volatile("cld; rep; insb" 209 : "+D" (addr), "+c" (count) 210 : "d" (port) 211 : "memory"); 212} 213 214static __inline void 215insw(u_int port, void *addr, size_t count) 216{ 217 __asm __volatile("cld; rep; insw" 218 : "+D" (addr), "+c" (count) 219 : "d" (port) 220 : "memory"); 221} 222 223static __inline void 224insl(u_int port, void *addr, size_t count) 225{ 226 __asm __volatile("cld; rep; insl" 227 : "+D" (addr), "+c" (count) 228 : "d" (port) 229 : "memory"); 230} 231 232static __inline void 233invd(void) 234{ 235 __asm __volatile("invd"); 236} 237 238static __inline u_short 239inw(u_int port) 240{ 241 u_short data; 242 243 __asm __volatile("inw %w1, %0" : "=a" (data) : "Nd" (port)); 244 return (data); 245} 246 247static __inline void 248outb(u_int port, u_char data) 249{ 250 __asm __volatile("outb %0, %w1" : : "a" (data), "Nd" (port)); 251} 252 253static __inline void 254outl(u_int port, u_int data) 255{ 256 __asm __volatile("outl %0, %w1" : : "a" (data), "Nd" (port)); 257} 258 259static __inline void 260outsb(u_int port, const void *addr, size_t count) 261{ 262 __asm __volatile("cld; rep; outsb" 263 : "+S" (addr), "+c" (count) 264 : "d" (port)); 265} 266 267static __inline void 268outsw(u_int port, const void *addr, size_t count) 269{ 270 __asm __volatile("cld; rep; outsw" 271 : "+S" (addr), "+c" (count) 272 : "d" (port)); 273} 274 275static __inline void 276outsl(u_int port, const void *addr, size_t count) 277{ 278 __asm __volatile("cld; rep; outsl" 279 : "+S" (addr), "+c" (count) 280 : "d" (port)); 281} 282 283static __inline void 284outw(u_int port, u_short data) 285{ 286 __asm __volatile("outw %0, %w1" : : "a" (data), "Nd" (port)); 287} 288 289static __inline void 290ia32_pause(void) 291{ 292 __asm __volatile("pause"); 293} 294 295static __inline u_int 296#ifdef XEN 297_read_eflags(void) 298#else 299read_eflags(void) 300#endif 301{ 302 u_int ef; 303 304 __asm __volatile("pushfl; popl %0" : "=r" (ef)); 305 return (ef); 306} 307 308static __inline uint64_t 309rdmsr(u_int msr) 310{ 311 uint64_t rv; 312 313 __asm __volatile("rdmsr" : "=A" (rv) : "c" (msr)); 314 return (rv); 315} 316 317static __inline uint64_t 318rdpmc(u_int pmc) 319{ 320 uint64_t rv; 321 322 __asm __volatile("rdpmc" : "=A" (rv) : "c" (pmc)); 323 return (rv); 324} 325 326static __inline uint64_t 327rdtsc(void) 328{ 329 uint64_t rv; 330 331 __asm __volatile("rdtsc" : "=A" (rv)); 332 return (rv); 333} 334 335static __inline void 336wbinvd(void) 337{ 338 __asm __volatile("wbinvd"); 339} 340 341static __inline void 342#ifdef XEN 343_write_eflags(u_int ef) 344#else 345write_eflags(u_int ef) 346#endif 347{ 348 __asm __volatile("pushl %0; popfl" : : "r" (ef)); 349} 350 351static __inline void 352wrmsr(u_int msr, uint64_t newval) 353{ 354 __asm __volatile("wrmsr" : : "A" (newval), "c" (msr)); 355} 356 357static __inline void 358load_cr0(u_int data) 359{ 360 361 __asm __volatile("movl %0,%%cr0" : : "r" (data)); 362} 363 364static __inline u_int 365rcr0(void) 366{ 367 u_int data; 368 369 __asm __volatile("movl %%cr0,%0" : "=r" (data)); 370 return (data); 371} 372 373static __inline u_int 374rcr2(void) 375{ 376 u_int data; 377 378#ifdef XEN 379 return (xen_rcr2()); 380#endif 381 __asm __volatile("movl %%cr2,%0" : "=r" (data)); 382 return (data); 383} 384 385static __inline void 386load_cr3(u_int data) 387{ 388#ifdef XEN 389 xen_load_cr3(data); 390#else 391 __asm __volatile("movl %0,%%cr3" : : "r" (data) : "memory"); 392#endif 393} 394 395static __inline u_int 396rcr3(void) 397{ 398 u_int data; 399 400 __asm __volatile("movl %%cr3,%0" : "=r" (data)); 401 return (data); 402} 403 404static __inline void 405load_cr4(u_int data) 406{ 407 __asm __volatile("movl %0,%%cr4" : : "r" (data)); 408} 409 410static __inline u_int 411rcr4(void) 412{ 413 u_int data; 414 415 __asm __volatile("movl %%cr4,%0" : "=r" (data)); 416 return (data); 417} 418 419/* 420 * Global TLB flush (except for thise for pages marked PG_G) 421 */ 422static __inline void 423invltlb(void) 424{ 425#ifdef XEN 426 xen_tlb_flush(); 427#else 428 load_cr3(rcr3()); 429#endif 430} 431 432/* 433 * TLB flush for an individual page (even if it has PG_G). 434 * Only works on 486+ CPUs (i386 does not have PG_G). 435 */ 436static __inline void 437invlpg(u_int addr) 438{ 439 440#ifdef XEN 441 xen_invlpg(addr); 442#else 443 __asm __volatile("invlpg %0" : : "m" (*(char *)addr) : "memory"); 444#endif 445} 446 447static __inline u_short 448rfs(void) 449{ 450 u_short sel; 451 __asm __volatile("movw %%fs,%0" : "=rm" (sel)); 452 return (sel); 453} 454 455static __inline uint64_t 456rgdt(void) 457{ 458 uint64_t gdtr; 459 __asm __volatile("sgdt %0" : "=m" (gdtr)); 460 return (gdtr); 461} 462 463static __inline u_short 464rgs(void) 465{ 466 u_short sel; 467 __asm __volatile("movw %%gs,%0" : "=rm" (sel)); 468 return (sel); 469} 470 471static __inline uint64_t 472ridt(void) 473{ 474 uint64_t idtr; 475 __asm __volatile("sidt %0" : "=m" (idtr)); 476 return (idtr); 477} 478 479static __inline u_short 480rldt(void) 481{ 482 u_short ldtr; 483 __asm __volatile("sldt %0" : "=g" (ldtr)); 484 return (ldtr); 485} 486 487static __inline u_short 488rss(void) 489{ 490 u_short sel; 491 __asm __volatile("movw %%ss,%0" : "=rm" (sel)); 492 return (sel); 493} 494 495static __inline u_short 496rtr(void) 497{ 498 u_short tr; 499 __asm __volatile("str %0" : "=g" (tr)); 500 return (tr); 501} 502 503static __inline void 504load_fs(u_short sel) 505{ 506 __asm __volatile("movw %0,%%fs" : : "rm" (sel)); 507} 508 509static __inline void 510load_gs(u_short sel) 511{ 512 __asm __volatile("movw %0,%%gs" : : "rm" (sel)); 513} 514 515static __inline void 516lidt(struct region_descriptor *addr) 517{ 518 __asm __volatile("lidt (%0)" : : "r" (addr)); 519} 520 521static __inline void 522lldt(u_short sel) 523{ 524 __asm __volatile("lldt %0" : : "r" (sel)); 525} 526 527static __inline void 528ltr(u_short sel) 529{ 530 __asm __volatile("ltr %0" : : "r" (sel)); 531} 532 533static __inline u_int 534rdr0(void) 535{ 536 u_int data; 537 __asm __volatile("movl %%dr0,%0" : "=r" (data)); 538 return (data); 539} 540 541static __inline void 542load_dr0(u_int dr0) 543{ 544 __asm __volatile("movl %0,%%dr0" : : "r" (dr0)); 545} 546 547static __inline u_int 548rdr1(void) 549{ 550 u_int data; 551 __asm __volatile("movl %%dr1,%0" : "=r" (data)); 552 return (data); 553} 554 555static __inline void 556load_dr1(u_int dr1) 557{ 558 __asm __volatile("movl %0,%%dr1" : : "r" (dr1)); 559} 560 561static __inline u_int 562rdr2(void) 563{ 564 u_int data; 565 __asm __volatile("movl %%dr2,%0" : "=r" (data)); 566 return (data); 567} 568 569static __inline void 570load_dr2(u_int dr2) 571{ 572 __asm __volatile("movl %0,%%dr2" : : "r" (dr2)); 573} 574 575static __inline u_int 576rdr3(void) 577{ 578 u_int data; 579 __asm __volatile("movl %%dr3,%0" : "=r" (data)); 580 return (data); 581} 582 583static __inline void 584load_dr3(u_int dr3) 585{ 586 __asm __volatile("movl %0,%%dr3" : : "r" (dr3)); 587} 588 589static __inline u_int 590rdr4(void) 591{ 592 u_int data; 593 __asm __volatile("movl %%dr4,%0" : "=r" (data)); 594 return (data); 595} 596 597static __inline void 598load_dr4(u_int dr4) 599{ 600 __asm __volatile("movl %0,%%dr4" : : "r" (dr4)); 601} 602 603static __inline u_int 604rdr5(void) 605{ 606 u_int data; 607 __asm __volatile("movl %%dr5,%0" : "=r" (data)); 608 return (data); 609} 610 611static __inline void 612load_dr5(u_int dr5) 613{ 614 __asm __volatile("movl %0,%%dr5" : : "r" (dr5)); 615} 616 617static __inline u_int 618rdr6(void) 619{ 620 u_int data; 621 __asm __volatile("movl %%dr6,%0" : "=r" (data)); 622 return (data); 623} 624 625static __inline void 626load_dr6(u_int dr6) 627{ 628 __asm __volatile("movl %0,%%dr6" : : "r" (dr6)); 629} 630 631static __inline u_int 632rdr7(void) 633{ 634 u_int data; 635 __asm __volatile("movl %%dr7,%0" : "=r" (data)); 636 return (data); 637} 638 639static __inline void 640load_dr7(u_int dr7) 641{ 642 __asm __volatile("movl %0,%%dr7" : : "r" (dr7)); 643} 644 645static __inline u_char 646read_cyrix_reg(u_char reg) 647{ 648 outb(0x22, reg); 649 return inb(0x23); 650} 651 652static __inline void 653write_cyrix_reg(u_char reg, u_char data) 654{ 655 outb(0x22, reg); 656 outb(0x23, data); 657} 658 659static __inline register_t 660intr_disable(void) 661{ 662 register_t eflags; 663 664 eflags = read_eflags(); 665 disable_intr(); 666 return (eflags); 667} 668 669static __inline void 670intr_restore(register_t eflags) 671{ 672 write_eflags(eflags); 673} 674 675#else /* !(__GNUCLIKE_ASM && __CC_SUPPORTS___INLINE) */ 676 677int breakpoint(void); 678u_int bsfl(u_int mask); 679u_int bsrl(u_int mask); 680void disable_intr(void); 681void do_cpuid(u_int ax, u_int *p); 682void enable_intr(void); 683void halt(void); 684void ia32_pause(void); 685u_char inb(u_int port); 686u_int inl(u_int port); 687void insb(u_int port, void *addr, size_t count); 688void insl(u_int port, void *addr, size_t count); 689void insw(u_int port, void *addr, size_t count); 690register_t intr_disable(void); 691void intr_restore(register_t ef); 692void invd(void); 693void invlpg(u_int addr); 694void invltlb(void); 695u_short inw(u_int port); 696void lidt(struct region_descriptor *addr); 697void lldt(u_short sel); 698void load_cr0(u_int cr0); 699void load_cr3(u_int cr3); 700void load_cr4(u_int cr4); 701void load_dr0(u_int dr0); 702void load_dr1(u_int dr1); 703void load_dr2(u_int dr2); 704void load_dr3(u_int dr3); 705void load_dr4(u_int dr4); 706void load_dr5(u_int dr5); 707void load_dr6(u_int dr6); 708void load_dr7(u_int dr7); 709void load_fs(u_short sel); 710void load_gs(u_short sel); 711void ltr(u_short sel); 712void outb(u_int port, u_char data); 713void outl(u_int port, u_int data); 714void outsb(u_int port, const void *addr, size_t count); 715void outsl(u_int port, const void *addr, size_t count); 716void outsw(u_int port, const void *addr, size_t count); 717void outw(u_int port, u_short data); 718u_int rcr0(void); 719u_int rcr2(void); 720u_int rcr3(void); 721u_int rcr4(void); 722uint64_t rdmsr(u_int msr); 723uint64_t rdpmc(u_int pmc); 724u_int rdr0(void); 725u_int rdr1(void); 726u_int rdr2(void); 727u_int rdr3(void); 728u_int rdr4(void); 729u_int rdr5(void); 730u_int rdr6(void); 731u_int rdr7(void); 732uint64_t rdtsc(void); 733u_char read_cyrix_reg(u_char reg); 734u_int read_eflags(void); 735u_int rfs(void); 736uint64_t rgdt(void); 737u_int rgs(void); 738uint64_t ridt(void); 739u_short rldt(void); 740u_short rtr(void); 741void wbinvd(void); 742void write_cyrix_reg(u_char reg, u_char data); 743void write_eflags(u_int ef); 744void wrmsr(u_int msr, uint64_t newval); 745 746#endif /* __GNUCLIKE_ASM && __CC_SUPPORTS___INLINE */ 747 748void reset_dbregs(void); 749 750#ifdef _KERNEL 751int rdmsr_safe(u_int msr, uint64_t *val); 752int wrmsr_safe(u_int msr, uint64_t newval); 753#endif 754 755#endif /* !_MACHINE_CPUFUNC_H_ */ 756