cpufunc.h revision 143063
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 143063 2005-03-02 21:33:29Z joerg $ 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 45struct region_descriptor; 46 47#define readb(va) (*(volatile u_int8_t *) (va)) 48#define readw(va) (*(volatile u_int16_t *) (va)) 49#define readl(va) (*(volatile u_int32_t *) (va)) 50 51#define writeb(va, d) (*(volatile u_int8_t *) (va) = (d)) 52#define writew(va, d) (*(volatile u_int16_t *) (va) = (d)) 53#define writel(va, d) (*(volatile u_int32_t *) (va) = (d)) 54 55#if defined(__GNUCLIKE_ASM) && defined(__CC_SUPPORTS___INLINE) 56 57static __inline void 58breakpoint(void) 59{ 60 __asm __volatile("int $3"); 61} 62 63static __inline u_int 64bsfl(u_int mask) 65{ 66 u_int result; 67 68 __asm __volatile("bsfl %1,%0" : "=r" (result) : "rm" (mask)); 69 return (result); 70} 71 72static __inline u_int 73bsrl(u_int mask) 74{ 75 u_int result; 76 77 __asm __volatile("bsrl %1,%0" : "=r" (result) : "rm" (mask)); 78 return (result); 79} 80 81static __inline void 82disable_intr(void) 83{ 84 __asm __volatile("cli" : : : "memory"); 85} 86 87static __inline void 88do_cpuid(u_int ax, u_int *p) 89{ 90 __asm __volatile("cpuid" 91 : "=a" (p[0]), "=b" (p[1]), "=c" (p[2]), "=d" (p[3]) 92 : "0" (ax)); 93} 94 95static __inline void 96enable_intr(void) 97{ 98 __asm __volatile("sti"); 99} 100 101#ifdef _KERNEL 102 103#define HAVE_INLINE_FFS 104 105static __inline int 106ffs(int mask) 107{ 108 /* 109 * Note that gcc-2's builtin ffs would be used if we didn't declare 110 * this inline or turn off the builtin. The builtin is faster but 111 * broken in gcc-2.4.5 and slower but working in gcc-2.5 and later 112 * versions. 113 */ 114 return (mask == 0 ? mask : (int)bsfl((u_int)mask) + 1); 115} 116 117#define HAVE_INLINE_FLS 118 119static __inline int 120fls(int mask) 121{ 122 return (mask == 0 ? mask : (int)bsrl((u_int)mask) + 1); 123} 124 125#endif /* _KERNEL */ 126 127static __inline void 128halt(void) 129{ 130 __asm __volatile("hlt"); 131} 132 133#if !defined(__GNUCLIKE_BUILTIN_CONSTANT_P) || __GNUCLIKE_ASM < 3 134 135#define inb(port) inbv(port) 136#define outb(port, data) outbv(port, data) 137 138#else /* __GNUCLIKE_BUILTIN_CONSTANT_P && __GNUCLIKE_ASM >= 3 */ 139 140/* 141 * The following complications are to get around gcc not having a 142 * constraint letter for the range 0..255. We still put "d" in the 143 * constraint because "i" isn't a valid constraint when the port 144 * isn't constant. This only matters for -O0 because otherwise 145 * the non-working version gets optimized away. 146 * 147 * Use an expression-statement instead of a conditional expression 148 * because gcc-2.6.0 would promote the operands of the conditional 149 * and produce poor code for "if ((inb(var) & const1) == const2)". 150 * 151 * The unnecessary test `(port) < 0x10000' is to generate a warning if 152 * the `port' has type u_short or smaller. Such types are pessimal. 153 * This actually only works for signed types. The range check is 154 * careful to avoid generating warnings. 155 */ 156#define inb(port) __extension__ ({ \ 157 u_char _data; \ 158 if (__builtin_constant_p(port) && ((port) & 0xffff) < 0x100 \ 159 && (port) < 0x10000) \ 160 _data = inbc(port); \ 161 else \ 162 _data = inbv(port); \ 163 _data; }) 164 165#define outb(port, data) ( \ 166 __builtin_constant_p(port) && ((port) & 0xffff) < 0x100 \ 167 && (port) < 0x10000 \ 168 ? outbc(port, data) : outbv(port, data)) 169 170static __inline u_char 171inbc(u_int port) 172{ 173 u_char data; 174 175 __asm __volatile("inb %1,%0" : "=a" (data) : "id" ((u_short)(port))); 176 return (data); 177} 178 179static __inline void 180outbc(u_int port, u_char data) 181{ 182 __asm __volatile("outb %0,%1" : : "a" (data), "id" ((u_short)(port))); 183} 184 185#endif /* __GNUCLIKE_BUILTIN_CONSTANT_P && __GNUCLIKE_ASM >= 3*/ 186 187static __inline u_char 188inbv(u_int port) 189{ 190 u_char data; 191 /* 192 * We use %%dx and not %1 here because i/o is done at %dx and not at 193 * %edx, while gcc generates inferior code (movw instead of movl) 194 * if we tell it to load (u_short) port. 195 */ 196 __asm __volatile("inb %%dx,%0" : "=a" (data) : "d" (port)); 197 return (data); 198} 199 200static __inline u_int 201inl(u_int port) 202{ 203 u_int data; 204 205 __asm __volatile("inl %%dx,%0" : "=a" (data) : "d" (port)); 206 return (data); 207} 208 209static __inline void 210insb(u_int port, void *addr, size_t cnt) 211{ 212 __asm __volatile("cld; rep; insb" 213 : "+D" (addr), "+c" (cnt) 214 : "d" (port) 215 : "memory"); 216} 217 218static __inline void 219insw(u_int port, void *addr, size_t cnt) 220{ 221 __asm __volatile("cld; rep; insw" 222 : "+D" (addr), "+c" (cnt) 223 : "d" (port) 224 : "memory"); 225} 226 227static __inline void 228insl(u_int port, void *addr, size_t cnt) 229{ 230 __asm __volatile("cld; rep; insl" 231 : "+D" (addr), "+c" (cnt) 232 : "d" (port) 233 : "memory"); 234} 235 236static __inline void 237invd(void) 238{ 239 __asm __volatile("invd"); 240} 241 242static __inline u_short 243inw(u_int port) 244{ 245 u_short data; 246 247 __asm __volatile("inw %%dx,%0" : "=a" (data) : "d" (port)); 248 return (data); 249} 250 251static __inline void 252outbv(u_int port, u_char data) 253{ 254 u_char al; 255 /* 256 * Use an unnecessary assignment to help gcc's register allocator. 257 * This make a large difference for gcc-1.40 and a tiny difference 258 * for gcc-2.6.0. For gcc-1.40, al had to be ``asm("ax")'' for 259 * best results. gcc-2.6.0 can't handle this. 260 */ 261 al = data; 262 __asm __volatile("outb %0,%%dx" : : "a" (al), "d" (port)); 263} 264 265static __inline void 266outl(u_int port, u_int data) 267{ 268 /* 269 * outl() and outw() aren't used much so we haven't looked at 270 * possible micro-optimizations such as the unnecessary 271 * assignment for them. 272 */ 273 __asm __volatile("outl %0,%%dx" : : "a" (data), "d" (port)); 274} 275 276static __inline void 277outsb(u_int port, const void *addr, size_t cnt) 278{ 279 __asm __volatile("cld; rep; outsb" 280 : "+S" (addr), "+c" (cnt) 281 : "d" (port)); 282} 283 284static __inline void 285outsw(u_int port, const void *addr, size_t cnt) 286{ 287 __asm __volatile("cld; rep; outsw" 288 : "+S" (addr), "+c" (cnt) 289 : "d" (port)); 290} 291 292static __inline void 293outsl(u_int port, const void *addr, size_t cnt) 294{ 295 __asm __volatile("cld; rep; outsl" 296 : "+S" (addr), "+c" (cnt) 297 : "d" (port)); 298} 299 300static __inline void 301outw(u_int port, u_short data) 302{ 303 __asm __volatile("outw %0,%%dx" : : "a" (data), "d" (port)); 304} 305 306static __inline void 307ia32_pause(void) 308{ 309 __asm __volatile("pause"); 310} 311 312static __inline u_int 313read_eflags(void) 314{ 315 u_int ef; 316 317 __asm __volatile("pushfl; popl %0" : "=r" (ef)); 318 return (ef); 319} 320 321static __inline u_int64_t 322rdmsr(u_int msr) 323{ 324 u_int64_t rv; 325 326 __asm __volatile("rdmsr" : "=A" (rv) : "c" (msr)); 327 return (rv); 328} 329 330static __inline u_int64_t 331rdpmc(u_int pmc) 332{ 333 u_int64_t rv; 334 335 __asm __volatile("rdpmc" : "=A" (rv) : "c" (pmc)); 336 return (rv); 337} 338 339static __inline u_int64_t 340rdtsc(void) 341{ 342 u_int64_t rv; 343 344 __asm __volatile("rdtsc" : "=A" (rv)); 345 return (rv); 346} 347 348static __inline void 349wbinvd(void) 350{ 351 __asm __volatile("wbinvd"); 352} 353 354static __inline void 355write_eflags(u_int ef) 356{ 357 __asm __volatile("pushl %0; popfl" : : "r" (ef)); 358} 359 360static __inline void 361wrmsr(u_int msr, u_int64_t newval) 362{ 363 __asm __volatile("wrmsr" : : "A" (newval), "c" (msr)); 364} 365 366static __inline void 367load_cr0(u_int data) 368{ 369 370 __asm __volatile("movl %0,%%cr0" : : "r" (data)); 371} 372 373static __inline u_int 374rcr0(void) 375{ 376 u_int data; 377 378 __asm __volatile("movl %%cr0,%0" : "=r" (data)); 379 return (data); 380} 381 382static __inline u_int 383rcr2(void) 384{ 385 u_int data; 386 387 __asm __volatile("movl %%cr2,%0" : "=r" (data)); 388 return (data); 389} 390 391static __inline void 392load_cr3(u_int data) 393{ 394 395 __asm __volatile("movl %0,%%cr3" : : "r" (data) : "memory"); 396} 397 398static __inline u_int 399rcr3(void) 400{ 401 u_int data; 402 403 __asm __volatile("movl %%cr3,%0" : "=r" (data)); 404 return (data); 405} 406 407static __inline void 408load_cr4(u_int data) 409{ 410 __asm __volatile("movl %0,%%cr4" : : "r" (data)); 411} 412 413static __inline u_int 414rcr4(void) 415{ 416 u_int data; 417 418 __asm __volatile("movl %%cr4,%0" : "=r" (data)); 419 return (data); 420} 421 422/* 423 * Global TLB flush (except for thise for pages marked PG_G) 424 */ 425static __inline void 426invltlb(void) 427{ 428 429 load_cr3(rcr3()); 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 __asm __volatile("invlpg %0" : : "m" (*(char *)addr) : "memory"); 441} 442 443static __inline u_int 444rfs(void) 445{ 446 u_int sel; 447 __asm __volatile("movl %%fs,%0" : "=rm" (sel)); 448 return (sel); 449} 450 451static __inline u_int 452rgs(void) 453{ 454 u_int sel; 455 __asm __volatile("movl %%gs,%0" : "=rm" (sel)); 456 return (sel); 457} 458 459static __inline u_int 460rss(void) 461{ 462 u_int sel; 463 __asm __volatile("movl %%ss,%0" : "=rm" (sel)); 464 return (sel); 465} 466 467static __inline void 468load_fs(u_int sel) 469{ 470 __asm __volatile("movl %0,%%fs" : : "rm" (sel)); 471} 472 473static __inline void 474load_gs(u_int sel) 475{ 476 __asm __volatile("movl %0,%%gs" : : "rm" (sel)); 477} 478 479static __inline void 480lidt(struct region_descriptor *addr) 481{ 482 __asm __volatile("lidt (%0)" : : "r" (addr)); 483} 484 485static __inline void 486lldt(u_short sel) 487{ 488 __asm __volatile("lldt %0" : : "r" (sel)); 489} 490 491static __inline void 492ltr(u_short sel) 493{ 494 __asm __volatile("ltr %0" : : "r" (sel)); 495} 496 497static __inline u_int 498rdr0(void) 499{ 500 u_int data; 501 __asm __volatile("movl %%dr0,%0" : "=r" (data)); 502 return (data); 503} 504 505static __inline void 506load_dr0(u_int dr0) 507{ 508 __asm __volatile("movl %0,%%dr0" : : "r" (dr0)); 509} 510 511static __inline u_int 512rdr1(void) 513{ 514 u_int data; 515 __asm __volatile("movl %%dr1,%0" : "=r" (data)); 516 return (data); 517} 518 519static __inline void 520load_dr1(u_int dr1) 521{ 522 __asm __volatile("movl %0,%%dr1" : : "r" (dr1)); 523} 524 525static __inline u_int 526rdr2(void) 527{ 528 u_int data; 529 __asm __volatile("movl %%dr2,%0" : "=r" (data)); 530 return (data); 531} 532 533static __inline void 534load_dr2(u_int dr2) 535{ 536 __asm __volatile("movl %0,%%dr2" : : "r" (dr2)); 537} 538 539static __inline u_int 540rdr3(void) 541{ 542 u_int data; 543 __asm __volatile("movl %%dr3,%0" : "=r" (data)); 544 return (data); 545} 546 547static __inline void 548load_dr3(u_int dr3) 549{ 550 __asm __volatile("movl %0,%%dr3" : : "r" (dr3)); 551} 552 553static __inline u_int 554rdr4(void) 555{ 556 u_int data; 557 __asm __volatile("movl %%dr4,%0" : "=r" (data)); 558 return (data); 559} 560 561static __inline void 562load_dr4(u_int dr4) 563{ 564 __asm __volatile("movl %0,%%dr4" : : "r" (dr4)); 565} 566 567static __inline u_int 568rdr5(void) 569{ 570 u_int data; 571 __asm __volatile("movl %%dr5,%0" : "=r" (data)); 572 return (data); 573} 574 575static __inline void 576load_dr5(u_int dr5) 577{ 578 __asm __volatile("movl %0,%%dr5" : : "r" (dr5)); 579} 580 581static __inline u_int 582rdr6(void) 583{ 584 u_int data; 585 __asm __volatile("movl %%dr6,%0" : "=r" (data)); 586 return (data); 587} 588 589static __inline void 590load_dr6(u_int dr6) 591{ 592 __asm __volatile("movl %0,%%dr6" : : "r" (dr6)); 593} 594 595static __inline u_int 596rdr7(void) 597{ 598 u_int data; 599 __asm __volatile("movl %%dr7,%0" : "=r" (data)); 600 return (data); 601} 602 603static __inline void 604load_dr7(u_int dr7) 605{ 606 __asm __volatile("movl %0,%%dr7" : : "r" (dr7)); 607} 608 609static __inline register_t 610intr_disable(void) 611{ 612 register_t eflags; 613 614 eflags = read_eflags(); 615 disable_intr(); 616 return (eflags); 617} 618 619static __inline void 620intr_restore(register_t eflags) 621{ 622 write_eflags(eflags); 623} 624 625#else /* !(__GNUCLIKE_ASM && __CC_SUPPORTS___INLINE) */ 626 627int breakpoint(void); 628u_int bsfl(u_int mask); 629u_int bsrl(u_int mask); 630void disable_intr(void); 631void do_cpuid(u_int ax, u_int *p); 632void enable_intr(void); 633void halt(void); 634void ia32_pause(void); 635u_char inb(u_int port); 636u_int inl(u_int port); 637void insb(u_int port, void *addr, size_t cnt); 638void insl(u_int port, void *addr, size_t cnt); 639void insw(u_int port, void *addr, size_t cnt); 640register_t intr_disable(void); 641void intr_restore(register_t ef); 642void invd(void); 643void invlpg(u_int addr); 644void invltlb(void); 645u_short inw(u_int port); 646void lidt(struct region_descriptor *addr); 647void lldt(u_short sel); 648void load_cr0(u_int cr0); 649void load_cr3(u_int cr3); 650void load_cr4(u_int cr4); 651void load_dr0(u_int dr0); 652void load_dr1(u_int dr1); 653void load_dr2(u_int dr2); 654void load_dr3(u_int dr3); 655void load_dr4(u_int dr4); 656void load_dr5(u_int dr5); 657void load_dr6(u_int dr6); 658void load_dr7(u_int dr7); 659void load_fs(u_int sel); 660void load_gs(u_int sel); 661void ltr(u_short sel); 662void outb(u_int port, u_char data); 663void outl(u_int port, u_int data); 664void outsb(u_int port, const void *addr, size_t cnt); 665void outsl(u_int port, const void *addr, size_t cnt); 666void outsw(u_int port, const void *addr, size_t cnt); 667void outw(u_int port, u_short data); 668u_int rcr0(void); 669u_int rcr2(void); 670u_int rcr3(void); 671u_int rcr4(void); 672u_int64_t rdmsr(u_int msr); 673u_int64_t rdpmc(u_int pmc); 674u_int rdr0(void); 675u_int rdr1(void); 676u_int rdr2(void); 677u_int rdr3(void); 678u_int rdr4(void); 679u_int rdr5(void); 680u_int rdr6(void); 681u_int rdr7(void); 682u_int64_t rdtsc(void); 683u_int read_eflags(void); 684u_int rfs(void); 685u_int rgs(void); 686void wbinvd(void); 687void write_eflags(u_int ef); 688void wrmsr(u_int msr, u_int64_t newval); 689 690#endif /* __GNUCLIKE_ASM && __CC_SUPPORTS___INLINE */ 691 692void reset_dbregs(void); 693 694#endif /* !_MACHINE_CPUFUNC_H_ */ 695