cpufunc.h revision 194295
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 194295 2009-06-16 15:13:18Z jhb $ 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 int xen_save_and_cli(void); 53extern void xen_restore_flags(u_int eflags); 54#endif 55 56struct region_descriptor; 57 58#define readb(va) (*(volatile u_int8_t *) (va)) 59#define readw(va) (*(volatile u_int16_t *) (va)) 60#define readl(va) (*(volatile u_int32_t *) (va)) 61 62#define writeb(va, d) (*(volatile u_int8_t *) (va) = (d)) 63#define writew(va, d) (*(volatile u_int16_t *) (va) = (d)) 64#define writel(va, d) (*(volatile u_int32_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 93disable_intr(void) 94{ 95#ifdef XEN 96 xen_cli(); 97#else 98 __asm __volatile("cli" : : : "memory"); 99#endif 100} 101 102static __inline void 103do_cpuid(u_int ax, u_int *p) 104{ 105 __asm __volatile("cpuid" 106 : "=a" (p[0]), "=b" (p[1]), "=c" (p[2]), "=d" (p[3]) 107 : "0" (ax)); 108} 109 110static __inline void 111cpuid_count(u_int ax, u_int cx, u_int *p) 112{ 113 __asm __volatile("cpuid" 114 : "=a" (p[0]), "=b" (p[1]), "=c" (p[2]), "=d" (p[3]) 115 : "0" (ax), "c" (cx)); 116} 117 118static __inline void 119enable_intr(void) 120{ 121#ifdef XEN 122 xen_sti(); 123#else 124 __asm __volatile("sti"); 125#endif 126} 127 128static inline void 129cpu_monitor(const void *addr, int extensions, int hints) 130{ 131 __asm __volatile("monitor;" 132 : :"a" (addr), "c" (extensions), "d"(hints)); 133} 134 135static inline void 136cpu_mwait(int extensions, int hints) 137{ 138 __asm __volatile("mwait;" : :"a" (hints), "c" (extensions)); 139} 140 141#ifdef _KERNEL 142 143#define HAVE_INLINE_FFS 144 145static __inline int 146ffs(int mask) 147{ 148 /* 149 * Note that gcc-2's builtin ffs would be used if we didn't declare 150 * this inline or turn off the builtin. The builtin is faster but 151 * broken in gcc-2.4.5 and slower but working in gcc-2.5 and later 152 * versions. 153 */ 154 return (mask == 0 ? mask : (int)bsfl((u_int)mask) + 1); 155} 156 157#define HAVE_INLINE_FLS 158 159static __inline int 160fls(int mask) 161{ 162 return (mask == 0 ? mask : (int)bsrl((u_int)mask) + 1); 163} 164 165#endif /* _KERNEL */ 166 167static __inline void 168halt(void) 169{ 170 __asm __volatile("hlt"); 171} 172 173static __inline u_char 174inb(u_int port) 175{ 176 u_char data; 177 178 __asm volatile("inb %w1, %0" : "=a" (data) : "Nd" (port)); 179 return (data); 180} 181 182static __inline u_int 183inl(u_int port) 184{ 185 u_int data; 186 187 __asm volatile("inl %w1, %0" : "=a" (data) : "Nd" (port)); 188 return (data); 189} 190 191static __inline void 192insb(u_int port, void *addr, size_t cnt) 193{ 194 __asm __volatile("cld; rep; insb" 195 : "+D" (addr), "+c" (cnt) 196 : "d" (port) 197 : "memory"); 198} 199 200static __inline void 201insw(u_int port, void *addr, size_t cnt) 202{ 203 __asm __volatile("cld; rep; insw" 204 : "+D" (addr), "+c" (cnt) 205 : "d" (port) 206 : "memory"); 207} 208 209static __inline void 210insl(u_int port, void *addr, size_t cnt) 211{ 212 __asm __volatile("cld; rep; insl" 213 : "+D" (addr), "+c" (cnt) 214 : "d" (port) 215 : "memory"); 216} 217 218static __inline void 219invd(void) 220{ 221 __asm __volatile("invd"); 222} 223 224static __inline u_short 225inw(u_int port) 226{ 227 u_short data; 228 229 __asm volatile("inw %w1, %0" : "=a" (data) : "Nd" (port)); 230 return (data); 231} 232 233static __inline void 234outb(u_int port, u_char data) 235{ 236 __asm __volatile("outb %0, %w1" : : "a" (data), "Nd" (port)); 237} 238 239static __inline void 240outl(u_int port, u_int data) 241{ 242 __asm volatile("outl %0, %w1" : : "a" (data), "Nd" (port)); 243} 244 245static __inline void 246outsb(u_int port, const void *addr, size_t cnt) 247{ 248 __asm __volatile("cld; rep; outsb" 249 : "+S" (addr), "+c" (cnt) 250 : "d" (port)); 251} 252 253static __inline void 254outsw(u_int port, const void *addr, size_t cnt) 255{ 256 __asm __volatile("cld; rep; outsw" 257 : "+S" (addr), "+c" (cnt) 258 : "d" (port)); 259} 260 261static __inline void 262outsl(u_int port, const void *addr, size_t cnt) 263{ 264 __asm __volatile("cld; rep; outsl" 265 : "+S" (addr), "+c" (cnt) 266 : "d" (port)); 267} 268 269static __inline void 270outw(u_int port, u_short data) 271{ 272 __asm volatile("outw %0, %w1" : : "a" (data), "Nd" (port)); 273} 274 275static __inline void 276ia32_pause(void) 277{ 278 __asm __volatile("pause"); 279} 280 281static __inline u_int 282read_eflags(void) 283{ 284 u_int ef; 285 286 __asm __volatile("pushfl; popl %0" : "=r" (ef)); 287 return (ef); 288} 289 290static __inline uint64_t 291rdmsr(u_int msr) 292{ 293 uint64_t rv; 294 295 __asm __volatile("rdmsr" : "=A" (rv) : "c" (msr)); 296 return (rv); 297} 298 299static __inline uint64_t 300rdpmc(u_int pmc) 301{ 302 uint64_t rv; 303 304 __asm __volatile("rdpmc" : "=A" (rv) : "c" (pmc)); 305 return (rv); 306} 307 308static __inline uint64_t 309rdtsc(void) 310{ 311 uint64_t rv; 312 313 __asm __volatile("rdtsc" : "=A" (rv)); 314 return (rv); 315} 316 317static __inline void 318wbinvd(void) 319{ 320 __asm __volatile("wbinvd"); 321} 322 323static __inline void 324write_eflags(u_int ef) 325{ 326 __asm __volatile("pushl %0; popfl" : : "r" (ef)); 327} 328 329static __inline void 330wrmsr(u_int msr, uint64_t newval) 331{ 332 __asm __volatile("wrmsr" : : "A" (newval), "c" (msr)); 333} 334 335static __inline void 336load_cr0(u_int data) 337{ 338 339 __asm __volatile("movl %0,%%cr0" : : "r" (data)); 340} 341 342static __inline u_int 343rcr0(void) 344{ 345 u_int data; 346 347 __asm __volatile("movl %%cr0,%0" : "=r" (data)); 348 return (data); 349} 350 351static __inline u_int 352rcr2(void) 353{ 354 u_int data; 355 356#ifdef XEN 357 return (xen_rcr2()); 358#endif 359 __asm __volatile("movl %%cr2,%0" : "=r" (data)); 360 return (data); 361} 362 363static __inline void 364load_cr3(u_int data) 365{ 366#ifdef XEN 367 xen_load_cr3(data); 368#else 369 __asm __volatile("movl %0,%%cr3" : : "r" (data) : "memory"); 370#endif 371} 372 373static __inline u_int 374rcr3(void) 375{ 376 u_int data; 377 378 __asm __volatile("movl %%cr3,%0" : "=r" (data)); 379 return (data); 380} 381 382static __inline void 383load_cr4(u_int data) 384{ 385 __asm __volatile("movl %0,%%cr4" : : "r" (data)); 386} 387 388static __inline u_int 389rcr4(void) 390{ 391 u_int data; 392 393 __asm __volatile("movl %%cr4,%0" : "=r" (data)); 394 return (data); 395} 396 397/* 398 * Global TLB flush (except for thise for pages marked PG_G) 399 */ 400static __inline void 401invltlb(void) 402{ 403#ifdef XEN 404 xen_tlb_flush(); 405#else 406 load_cr3(rcr3()); 407#endif 408} 409 410/* 411 * TLB flush for an individual page (even if it has PG_G). 412 * Only works on 486+ CPUs (i386 does not have PG_G). 413 */ 414static __inline void 415invlpg(u_int addr) 416{ 417 418#ifdef XEN 419 xen_invlpg(addr); 420#else 421 __asm __volatile("invlpg %0" : : "m" (*(char *)addr) : "memory"); 422#endif 423} 424 425static __inline u_int 426rfs(void) 427{ 428 u_int sel; 429 __asm __volatile("mov %%fs,%0" : "=rm" (sel)); 430 return (sel); 431} 432 433static __inline uint64_t 434rgdt(void) 435{ 436 uint64_t gdtr; 437 __asm __volatile("sgdt %0" : "=m" (gdtr)); 438 return (gdtr); 439} 440 441static __inline u_int 442rgs(void) 443{ 444 u_int sel; 445 __asm __volatile("mov %%gs,%0" : "=rm" (sel)); 446 return (sel); 447} 448 449static __inline uint64_t 450ridt(void) 451{ 452 uint64_t idtr; 453 __asm __volatile("sidt %0" : "=m" (idtr)); 454 return (idtr); 455} 456 457static __inline u_short 458rldt(void) 459{ 460 u_short ldtr; 461 __asm __volatile("sldt %0" : "=g" (ldtr)); 462 return (ldtr); 463} 464 465static __inline u_int 466rss(void) 467{ 468 u_int sel; 469 __asm __volatile("mov %%ss,%0" : "=rm" (sel)); 470 return (sel); 471} 472 473static __inline u_short 474rtr(void) 475{ 476 u_short tr; 477 __asm __volatile("str %0" : "=g" (tr)); 478 return (tr); 479} 480 481static __inline void 482load_fs(u_int sel) 483{ 484 __asm __volatile("mov %0,%%fs" : : "rm" (sel)); 485} 486 487static __inline void 488load_gs(u_int sel) 489{ 490 __asm __volatile("mov %0,%%gs" : : "rm" (sel)); 491} 492 493static __inline void 494lidt(struct region_descriptor *addr) 495{ 496 __asm __volatile("lidt (%0)" : : "r" (addr)); 497} 498 499static __inline void 500lldt(u_short sel) 501{ 502 __asm __volatile("lldt %0" : : "r" (sel)); 503} 504 505static __inline void 506ltr(u_short sel) 507{ 508 __asm __volatile("ltr %0" : : "r" (sel)); 509} 510 511static __inline u_int 512rdr0(void) 513{ 514 u_int data; 515 __asm __volatile("movl %%dr0,%0" : "=r" (data)); 516 return (data); 517} 518 519static __inline void 520load_dr0(u_int dr0) 521{ 522 __asm __volatile("movl %0,%%dr0" : : "r" (dr0)); 523} 524 525static __inline u_int 526rdr1(void) 527{ 528 u_int data; 529 __asm __volatile("movl %%dr1,%0" : "=r" (data)); 530 return (data); 531} 532 533static __inline void 534load_dr1(u_int dr1) 535{ 536 __asm __volatile("movl %0,%%dr1" : : "r" (dr1)); 537} 538 539static __inline u_int 540rdr2(void) 541{ 542 u_int data; 543 __asm __volatile("movl %%dr2,%0" : "=r" (data)); 544 return (data); 545} 546 547static __inline void 548load_dr2(u_int dr2) 549{ 550 __asm __volatile("movl %0,%%dr2" : : "r" (dr2)); 551} 552 553static __inline u_int 554rdr3(void) 555{ 556 u_int data; 557 __asm __volatile("movl %%dr3,%0" : "=r" (data)); 558 return (data); 559} 560 561static __inline void 562load_dr3(u_int dr3) 563{ 564 __asm __volatile("movl %0,%%dr3" : : "r" (dr3)); 565} 566 567static __inline u_int 568rdr4(void) 569{ 570 u_int data; 571 __asm __volatile("movl %%dr4,%0" : "=r" (data)); 572 return (data); 573} 574 575static __inline void 576load_dr4(u_int dr4) 577{ 578 __asm __volatile("movl %0,%%dr4" : : "r" (dr4)); 579} 580 581static __inline u_int 582rdr5(void) 583{ 584 u_int data; 585 __asm __volatile("movl %%dr5,%0" : "=r" (data)); 586 return (data); 587} 588 589static __inline void 590load_dr5(u_int dr5) 591{ 592 __asm __volatile("movl %0,%%dr5" : : "r" (dr5)); 593} 594 595static __inline u_int 596rdr6(void) 597{ 598 u_int data; 599 __asm __volatile("movl %%dr6,%0" : "=r" (data)); 600 return (data); 601} 602 603static __inline void 604load_dr6(u_int dr6) 605{ 606 __asm __volatile("movl %0,%%dr6" : : "r" (dr6)); 607} 608 609static __inline u_int 610rdr7(void) 611{ 612 u_int data; 613 __asm __volatile("movl %%dr7,%0" : "=r" (data)); 614 return (data); 615} 616 617static __inline void 618load_dr7(u_int dr7) 619{ 620 __asm __volatile("movl %0,%%dr7" : : "r" (dr7)); 621} 622 623static __inline u_char 624read_cyrix_reg(u_char reg) 625{ 626 outb(0x22, reg); 627 return inb(0x23); 628} 629 630static __inline void 631write_cyrix_reg(u_char reg, u_char data) 632{ 633 outb(0x22, reg); 634 outb(0x23, data); 635} 636 637static __inline register_t 638intr_disable(void) 639{ 640 register_t eflags; 641 642#ifdef XEN 643 eflags = xen_save_and_cli(); 644#else 645 eflags = read_eflags(); 646 disable_intr(); 647#endif 648 return (eflags); 649} 650 651static __inline void 652intr_restore(register_t eflags) 653{ 654#ifdef XEN 655 xen_restore_flags(eflags); 656#else 657 write_eflags(eflags); 658#endif 659} 660 661#else /* !(__GNUCLIKE_ASM && __CC_SUPPORTS___INLINE) */ 662 663int breakpoint(void); 664u_int bsfl(u_int mask); 665u_int bsrl(u_int mask); 666void disable_intr(void); 667void do_cpuid(u_int ax, u_int *p); 668void enable_intr(void); 669void halt(void); 670void ia32_pause(void); 671u_char inb(u_int port); 672u_int inl(u_int port); 673void insb(u_int port, void *addr, size_t cnt); 674void insl(u_int port, void *addr, size_t cnt); 675void insw(u_int port, void *addr, size_t cnt); 676register_t intr_disable(void); 677void intr_restore(register_t ef); 678void invd(void); 679void invlpg(u_int addr); 680void invltlb(void); 681u_short inw(u_int port); 682void lidt(struct region_descriptor *addr); 683void lldt(u_short sel); 684void load_cr0(u_int cr0); 685void load_cr3(u_int cr3); 686void load_cr4(u_int cr4); 687void load_dr0(u_int dr0); 688void load_dr1(u_int dr1); 689void load_dr2(u_int dr2); 690void load_dr3(u_int dr3); 691void load_dr4(u_int dr4); 692void load_dr5(u_int dr5); 693void load_dr6(u_int dr6); 694void load_dr7(u_int dr7); 695void load_fs(u_int sel); 696void load_gs(u_int sel); 697void ltr(u_short sel); 698void outb(u_int port, u_char data); 699void outl(u_int port, u_int data); 700void outsb(u_int port, const void *addr, size_t cnt); 701void outsl(u_int port, const void *addr, size_t cnt); 702void outsw(u_int port, const void *addr, size_t cnt); 703void outw(u_int port, u_short data); 704u_int rcr0(void); 705u_int rcr2(void); 706u_int rcr3(void); 707u_int rcr4(void); 708uint64_t rdmsr(u_int msr); 709uint64_t rdpmc(u_int pmc); 710u_int rdr0(void); 711u_int rdr1(void); 712u_int rdr2(void); 713u_int rdr3(void); 714u_int rdr4(void); 715u_int rdr5(void); 716u_int rdr6(void); 717u_int rdr7(void); 718uint64_t rdtsc(void); 719u_char read_cyrix_reg(u_char reg); 720u_int read_eflags(void); 721u_int rfs(void); 722uint64_t rgdt(void); 723u_int rgs(void); 724uint64_t ridt(void); 725u_short rldt(void); 726u_short rtr(void); 727void wbinvd(void); 728void write_cyrix_reg(u_char reg, u_char data); 729void write_eflags(u_int ef); 730void wrmsr(u_int msr, uint64_t newval); 731 732#endif /* __GNUCLIKE_ASM && __CC_SUPPORTS___INLINE */ 733 734void reset_dbregs(void); 735 736#ifdef _KERNEL 737int rdmsr_safe(u_int msr, uint64_t *val); 738int wrmsr_safe(u_int msr, uint64_t newval); 739#endif 740 741#endif /* !_MACHINE_CPUFUNC_H_ */ 742