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