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