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