cpufunc.h revision 12592
123925Sgibbs/*- 223925Sgibbs * Copyright (c) 1993 The Regents of the University of California. 323925Sgibbs * All rights reserved. 455581Sgibbs * 523925Sgibbs * Redistribution and use in source and binary forms, with or without 623925Sgibbs * modification, are permitted provided that the following conditions 723925Sgibbs * are met: 823925Sgibbs * 1. Redistributions of source code must retain the above copyright 923925Sgibbs * notice, this list of conditions and the following disclaimer. 1023925Sgibbs * 2. Redistributions in binary form must reproduce the above copyright 1126997Sgibbs * notice, this list of conditions and the following disclaimer in the 1254211Sgibbs * documentation and/or other materials provided with the distribution. 1339220Sgibbs * 3. All advertising materials mentioning features or use of this software 1423925Sgibbs * must display the following acknowledgement: 1523925Sgibbs * This product includes software developed by the University of 1654211Sgibbs * California, Berkeley and its contributors. 1763457Sgibbs * 4. Neither the name of the University nor the names of its contributors 1826997Sgibbs * may be used to endorse or promote products derived from this software 1923925Sgibbs * without specific prior written permission. 2023925Sgibbs * 2123925Sgibbs * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 2223925Sgibbs * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2323925Sgibbs * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2423925Sgibbs * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 2523925Sgibbs * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2623925Sgibbs * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2723925Sgibbs * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2823925Sgibbs * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2923925Sgibbs * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3023925Sgibbs * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3165942Sgibbs * SUCH DAMAGE. 3265942Sgibbs * 3350477Speter * $Id: cpufunc.h,v 1.41 1995/10/05 10:32:47 phk Exp $ 3423925Sgibbs */ 3523925Sgibbs 3623925Sgibbs/* 3723925Sgibbs * Functions to provide access to special i386 instructions. 3823925Sgibbs */ 3923925Sgibbs 4023925Sgibbs#ifndef _MACHINE_CPUFUNC_H_ 4123925Sgibbs#define _MACHINE_CPUFUNC_H_ 4223925Sgibbs 4323925Sgibbs#include <sys/cdefs.h> 4423925Sgibbs#include <sys/types.h> 4523925Sgibbs 4623925Sgibbs#include <machine/spl.h> /* XXX belongs elsewhere */ 4723925Sgibbs 4823925Sgibbs#ifdef __GNUC__ 4923925Sgibbs 5023925Sgibbs#ifdef BDE_DEBUGGER 5123925Sgibbsextern int bdb_exists; 5223925Sgibbs 5323925Sgibbsstatic __inline int 5423925Sgibbsbdb(void) 5523925Sgibbs{ 5623925Sgibbs if (!bdb_exists) 5723925Sgibbs return (0); 5823925Sgibbs __asm __volatile("int $3"); 5923925Sgibbs return (1); 6023925Sgibbs} 6123925Sgibbs#endif /* BDE_DEBUGGER */ 6223925Sgibbs 6323925Sgibbsstatic __inline void 6423925Sgibbsdisable_intr(void) 6523925Sgibbs{ 6623925Sgibbs __asm __volatile("cli" : : : "memory"); 6723925Sgibbs} 6823925Sgibbs 6923925Sgibbsstatic __inline void 7023925Sgibbsenable_intr(void) 7123925Sgibbs{ 7223925Sgibbs __asm __volatile("sti"); 7323925Sgibbs} 7423925Sgibbs 7523925Sgibbs#define HAVE_INLINE_FFS 7623925Sgibbs 7723925Sgibbsstatic __inline int 7823925Sgibbsffs(int mask) 7923925Sgibbs{ 8023925Sgibbs int result; 8123925Sgibbs /* 8223925Sgibbs * bsfl turns out to be not all that slow on 486's. It can beaten 8323925Sgibbs * using a binary search to reduce to 4 bits and then a table lookup, 8423925Sgibbs * but only if the code is inlined and in the cache, and the code 8523925Sgibbs * is quite large so inlining it probably busts the cache. 8623925Sgibbs * 8723925Sgibbs * Note that gcc-2's builtin ffs would be used if we didn't declare 8823925Sgibbs * this inline or turn off the builtin. The builtin is faster but 8923925Sgibbs * broken in gcc-2.4.5 and slower but working in gcc-2.5 and 2.6. 9023925Sgibbs */ 9123925Sgibbs __asm __volatile("testl %0,%0; je 1f; bsfl %0,%0; incl %0; 1:" 9223925Sgibbs : "=r" (result) : "0" (mask)); 9323925Sgibbs return (result); 9423925Sgibbs} 9523925Sgibbs 9623925Sgibbs#if __GNUC__ < 2 9723925Sgibbs 9823925Sgibbs#define inb(port) inbv(port) 9923925Sgibbs#define outb(port, data) outbv(port, data) 10023925Sgibbs 10123925Sgibbs#else /* __GNUC >= 2 */ 10223925Sgibbs 10323925Sgibbs/* 10423925Sgibbs * The following complications are to get around gcc not having a 10523925Sgibbs * constraint letter for the range 0..255. We still put "d" in the 10623925Sgibbs * constraint because "i" isn't a valid constraint when the port 10723925Sgibbs * isn't constant. This only matters for -O0 because otherwise 10823925Sgibbs * the non-working version gets optimized away. 10923925Sgibbs * 11023925Sgibbs * Use an expression-statement instead of a conditional expression 11123925Sgibbs * because gcc-2.6.0 would promote the operands of the conditional 11223925Sgibbs * and produce poor code for "if ((inb(var) & const1) == const2)". 11323925Sgibbs */ 11423925Sgibbs#define inb(port) ({ \ 11523925Sgibbs u_char _data; \ 11623925Sgibbs if (__builtin_constant_p((int) (port)) && (port) < 256ul) \ 11723925Sgibbs _data = inbc(port); \ 11823925Sgibbs else \ 11923925Sgibbs _data = inbv(port); \ 12023925Sgibbs _data; }) 12123925Sgibbs 12223925Sgibbs#define outb(port, data) \ 12323925Sgibbs (__builtin_constant_p((int) (port)) && (port) < 256ul \ 12423925Sgibbs ? outbc(port, data) : outbv(port, data)) 12523925Sgibbs 12623925Sgibbsstatic __inline u_char 12723925Sgibbsinbc(u_int port) 12823925Sgibbs{ 12923925Sgibbs u_char data; 13023925Sgibbs 13123925Sgibbs __asm __volatile("inb %1,%0" : "=a" (data) : "id" ((u_short)(port))); 13223925Sgibbs return (data); 13323925Sgibbs} 13423925Sgibbs 13523925Sgibbsstatic __inline void 13623925Sgibbsoutbc(u_int port, u_char data) 13723925Sgibbs{ 13823925Sgibbs __asm __volatile("outb %0,%1" : : "a" (data), "id" ((u_short)(port))); 13923925Sgibbs} 14023925Sgibbs 14123925Sgibbs#endif /* __GNUC <= 2 */ 14223925Sgibbs 14323925Sgibbsstatic __inline u_char 14423925Sgibbsinbv(u_int port) 14523925Sgibbs{ 14623925Sgibbs u_char data; 14723925Sgibbs /* 14823925Sgibbs * We use %%dx and not %1 here because i/o is done at %dx and not at 14923925Sgibbs * %edx, while gcc generates inferior code (movw instead of movl) 15023925Sgibbs * if we tell it to load (u_short) port. 15123925Sgibbs */ 15223925Sgibbs __asm __volatile("inb %%dx,%0" : "=a" (data) : "d" (port)); 15323925Sgibbs return (data); 15423925Sgibbs} 15523925Sgibbs 15623925Sgibbsstatic __inline u_long 15723925Sgibbsinl(u_int port) 15823925Sgibbs{ 15923925Sgibbs u_long data; 16023925Sgibbs 16155581Sgibbs __asm __volatile("inl %%dx,%0" : "=a" (data) : "d" (port)); 16255581Sgibbs return (data); 16323925Sgibbs} 16455581Sgibbs 16523925Sgibbsstatic __inline void 16623925Sgibbsinsb(u_int port, void *addr, size_t cnt) 16723925Sgibbs{ 16823925Sgibbs __asm __volatile("cld; rep; insb" 16923925Sgibbs : : "d" (port), "D" (addr), "c" (cnt) 17023925Sgibbs : "di", "cx", "memory"); 17123925Sgibbs} 17223925Sgibbs 17323925Sgibbsstatic __inline void 17423925Sgibbsinsw(u_int port, void *addr, size_t cnt) 17523925Sgibbs{ 17623925Sgibbs __asm __volatile("cld; rep; insw" 17763457Sgibbs : : "d" (port), "D" (addr), "c" (cnt) 17863457Sgibbs : "di", "cx", "memory"); 17923925Sgibbs} 18039220Sgibbs 18139220Sgibbsstatic __inline void 18239220Sgibbsinsl(u_int port, void *addr, size_t cnt) 18339220Sgibbs{ 18439220Sgibbs __asm __volatile("cld; rep; insl" 18539220Sgibbs : : "d" (port), "D" (addr), "c" (cnt) 18639220Sgibbs : "di", "cx", "memory"); 18723925Sgibbs} 18823925Sgibbs 18923925Sgibbsstatic __inline u_short 19023925Sgibbsinw(u_int port) 19123925Sgibbs{ 19223925Sgibbs u_short data; 19323925Sgibbs 19423925Sgibbs __asm __volatile("inw %%dx,%0" : "=a" (data) : "d" (port)); 19523925Sgibbs return (data); 19623925Sgibbs} 19723925Sgibbs 19823925Sgibbsstatic __inline unsigned 19923925Sgibbsloadandclear(u_int *addr) 20023925Sgibbs{ 20123925Sgibbs u_int result; 20223925Sgibbs 20323925Sgibbs __asm __volatile("xorl %0,%0; xchgl %1,%0" 20423925Sgibbs : "=&r" (result) : "m" (*addr)); 20523925Sgibbs return (result); 20623925Sgibbs} 20723925Sgibbs 20823925Sgibbsstatic __inline void 20923925Sgibbsoutbv(u_int port, u_char data) 21023925Sgibbs{ 21123925Sgibbs u_char al; 21223925Sgibbs /* 21323925Sgibbs * Use an unnecessary assignment to help gcc's register allocator. 21423925Sgibbs * This make a large difference for gcc-1.40 and a tiny difference 21523925Sgibbs * for gcc-2.6.0. For gcc-1.40, al had to be ``asm("ax")'' for 21623925Sgibbs * best results. gcc-2.6.0 can't handle this. 21723925Sgibbs */ 21855581Sgibbs al = data; 21955581Sgibbs __asm __volatile("outb %0,%%dx" : : "a" (al), "d" (port)); 22055581Sgibbs} 22155581Sgibbs 22255581Sgibbsstatic __inline void 22355581Sgibbsoutl(u_int port, u_long data) 22455581Sgibbs{ 22555581Sgibbs /* 22655581Sgibbs * outl() and outw() aren't used much so we haven't looked at 22755581Sgibbs * possible micro-optimizations such as the unnecessary 22855581Sgibbs * assignment for them. 22955581Sgibbs */ 23055581Sgibbs __asm __volatile("outl %0,%%dx" : : "a" (data), "d" (port)); 23155581Sgibbs} 23255581Sgibbs 23355581Sgibbsstatic __inline void 23455581Sgibbsoutsb(u_int port, void *addr, size_t cnt) 23555581Sgibbs{ 23655581Sgibbs __asm __volatile("cld; rep; outsb" 23755581Sgibbs : : "d" (port), "S" (addr), "c" (cnt) 23855581Sgibbs : "si", "cx"); 23955581Sgibbs} 24023925Sgibbs 24123925Sgibbsstatic __inline void 24223925Sgibbsoutsw(u_int port, void *addr, size_t cnt) 24323925Sgibbs{ 24423925Sgibbs __asm __volatile("cld; rep; outsw" 24523925Sgibbs : : "d" (port), "S" (addr), "c" (cnt) 24623925Sgibbs : "si", "cx"); 24723925Sgibbs} 24823925Sgibbs 24923925Sgibbsstatic __inline void 25023925Sgibbsoutsl(u_int port, void *addr, size_t cnt) 25123925Sgibbs{ 25223925Sgibbs __asm __volatile("cld; rep; outsl" 25323925Sgibbs : : "d" (port), "S" (addr), "c" (cnt) 25423925Sgibbs : "si", "cx"); 25523925Sgibbs} 25623925Sgibbs 25723925Sgibbsstatic __inline void 25823925Sgibbsoutw(u_int port, u_short data) 25923925Sgibbs{ 26023925Sgibbs __asm __volatile("outw %0,%%dx" : : "a" (data), "d" (port)); 26123925Sgibbs} 26239220Sgibbs 26339220Sgibbsstatic __inline void 26439220Sgibbspmap_update(void) 26539220Sgibbs{ 26639220Sgibbs u_long temp; 26739220Sgibbs /* 26839220Sgibbs * This should be implemented as load_cr3(rcr3()) when load_cr3() 26939220Sgibbs * is inlined. 27039220Sgibbs */ 27123925Sgibbs __asm __volatile("movl %%cr3, %0; movl %0, %%cr3" : "=r" (temp) 27223925Sgibbs : : "memory"); 27323925Sgibbs} 27423925Sgibbs 27523925Sgibbsstatic __inline u_long 27623925Sgibbsrcr2(void) 27723925Sgibbs{ 27823925Sgibbs u_long data; 27923925Sgibbs 28023925Sgibbs __asm __volatile("movl %%cr2,%0" : "=r" (data)); 28123925Sgibbs return (data); 28223925Sgibbs} 28323925Sgibbs 28423925Sgibbsstatic __inline u_long 28523925Sgibbsread_eflags(void) 28623925Sgibbs{ 28723925Sgibbs u_long ef; 28823925Sgibbs 28923925Sgibbs __asm __volatile("pushfl; popl %0" : "=r" (ef)); 29023925Sgibbs return (ef); 29123925Sgibbs} 29223925Sgibbs 29323925Sgibbsstatic __inline void 29423925Sgibbswrite_eflags(u_long ef) 29523925Sgibbs{ 29623925Sgibbs __asm __volatile("pushl %0; popfl" : : "r" (ef)); 29723925Sgibbs} 29823925Sgibbs 29923925Sgibbs#else /* !__GNUC__ */ 30023925Sgibbs 30123925Sgibbsint bdb __P((void)); 30223925Sgibbsvoid disable_intr __P((void)); 30323925Sgibbsvoid enable_intr __P((void)); 30423925Sgibbsu_char inb __P((u_int port)); 30523925Sgibbsu_long inl __P((u_int port)); 30623925Sgibbsvoid insb __P((u_int port, void *addr, size_t cnt)); 30723925Sgibbsvoid insl __P((u_int port, void *addr, size_t cnt)); 30823925Sgibbsvoid insw __P((u_int port, void *addr, size_t cnt)); 30923925Sgibbsu_short inw __P((u_int port)); 31023925Sgibbsu_int loadandclear __P((u_int *addr)); 31123925Sgibbsvoid outb __P((u_int port, u_char data)); 31263944Sgibbsvoid outl __P((u_int port, u_long data)); 31339220Sgibbsvoid outsb __P((u_int port, void *addr, size_t cnt)); 31423925Sgibbsvoid outsl __P((u_int port, void *addr, size_t cnt)); 31523925Sgibbsvoid outsw __P((u_int port, void *addr, size_t cnt)); 31623925Sgibbsvoid outw __P((u_int port, u_short data)); 31723925Sgibbsvoid pmap_update __P((void)); 31823925Sgibbsu_long read_eflags __P((void)); 31923925Sgibbsu_long rcr2 __P((void)); 32023925Sgibbsvoid write_eflags __P((u_long ef)); 32123925Sgibbs 32223925Sgibbs#endif /* __GNUC__ */ 32323925Sgibbs 32423925Sgibbs/* 32523925Sgibbs * XXX the following declarations document garbage in support.s. 32623925Sgibbs * bcopy[bwx]() was used by pccons but isn't used now. 32723925Sgibbs */ 32839220Sgibbsvoid bcopyb __P((const void *from, void *to, size_t len)); 32923925Sgibbsvoid bcopyw __P((const void *from, void *to, size_t len)); 33039220Sgibbsvoid bcopyx __P((const void *from, void *to, size_t len, 33123925Sgibbs int stride)); 33223925Sgibbs 33339220Sgibbs#if 0 33439220Sgibbs/* 33523925Sgibbs * These functions in support.s are declared elsewhere. 33623925Sgibbs */ 33723925Sgibbsvoid bcopy __P((const void *from, void *to, size_t len)); 33823925Sgibbsvoid blkclr __P((void *buf, size_t len)); 33923925Sgibbsvoid bzero __P((void *buf, size_t len)); 34023925Sgibbsint copyin __P((void *udaddr, void *kaddr, size_t len)); 34123925Sgibbsint copyinstr __P((void *udaddr, void *kaddr, size_t len, 34223925Sgibbs size_t *lencopied)); 34323925Sgibbsint copyout __P((void *kaddr, void *udaddr, size_t len)); 34423925Sgibbsint copystr __P((void *kfaddr, void *kdaddr, size_t len, 34523925Sgibbs size_t *lencopied)); 34623925Sgibbsint fubyte __P((void *base)); 34723925Sgibbsint fuswintr __P((void *base)); 34823925Sgibbsint fuibyte __P((void *base)); 34939220Sgibbsint fuword __P((void *base)); 35023925Sgibbsstruct region_descriptor; 35123925Sgibbsvoid lgdt __P((struct region_descriptor *rdp)); 35223925Sgibbsvoid lidt __P((struct region_descriptor *rdp)); 35323925Sgibbsvoid lldt __P((u_short sel)); 35423925Sgibbs/* 35523925Sgibbs * longjmp() and setjmp() are only used by ddb. They probably shouldn't 35623925Sgibbs * shouldn't be supported in the kernel. 35723925Sgibbs */ 35823925Sgibbs#include <setjmp.h> 35923925Sgibbsvoid longjmp __P((jmp_buf jb, int rv)); 36023925Sgibbsvoid ovbcopy __P((const void *from, void *to, size_t len); 36123925Sgibbsint setjmp __P((jmp_buf jb)); 36223925Sgibbsstruct soft_segment_descriptor; 36323925Sgibbsunion descriptor; 36423925Sgibbsint ssdtosd __P((struct soft_segment_descriptor *ssdp, 36523925Sgibbs union descriptor *sdp)); 36623925Sgibbsint subyte __P((void *base, int byte)); 36723925Sgibbsint suibyte __P((void *base, int byte)); 36823925Sgibbsint suswintr __P((void *base, int word)); 36923925Sgibbsint suword __P((void *base, int word)); 37023925Sgibbs 37123925Sgibbs/* 37223925Sgibbs * These functions in support.s are declared elsewhere, but never used. 37323925Sgibbs * A silly amount of effort went into copyoutstr(). It's not worth 37423925Sgibbs * maintaining, since the string length is usually known so copyout 37523925Sgibbs * works better, or is easy to find so copyout() can be used. 37623925Sgibbs */ 37723925Sgibbsint copyoutstr __P((void *kaddr, void *udaddr, size_t len, 37823925Sgibbs size_t *lencopied)); 37923925Sgibbsint fuiword __P((void *base)); 38023925Sgibbsint suiword __P((void *base, int word)); 38123925Sgibbs 38223925Sgibbs/* 38323925Sgibbs * These functions in support.s are also in libkern.a and are declared in 38423925Sgibbs * libkern.h. 38523925Sgibbs * ffs() is built in to gcc-2 and was buggy in gcc-2.4.5 so we may may the 38623925Sgibbs * buggy version if we don't replace it by an inline. 38723925Sgibbs */ 38823925Sgibbsint bcmp __P((const void *b1, const void *b2, size_t length)); 38923925Sgibbsint ffs __P((int mask)); 39023925Sgibbs#endif /* 0 */ 39123925Sgibbs 39223925Sgibbs/* 39323925Sgibbs * These variables and functions in support.s are used. 39423925Sgibbs */ 39523925Sgibbsextern u_int atdevbase; /* offset in virtual memory of ISA io mem */ 39623925Sgibbs 39723925Sgibbsvoid filli __P((int pat, void *base, size_t cnt)); 39823925Sgibbsvoid fillw __P((int /*u_short*/ pat, void *base, size_t cnt)); 39923925Sgibbsint fusword __P((void *base)); 40023925Sgibbsvoid load_cr0 __P((u_long cr0)); 40123925Sgibbsvoid load_cr3 __P((u_long cr3)); 40223925Sgibbsvoid ltr __P((u_short sel)); 40323925Sgibbsu_int rcr0 __P((void)); 40423925Sgibbsu_long rcr3 __P((void)); 40523925Sgibbsint rtcin __P((int val)); 40623925Sgibbs 40723925Sgibbs/* 40823925Sgibbs * These functions are NOT in support.s and should be declared elsewhere. 40923925Sgibbs */ 41023925Sgibbsvoid Debugger __P((const char *msg)); 41123925Sgibbsu_long kvtop __P((void *addr)); 41223925Sgibbstypedef void alias_for_inthand_t __P((u_int cs, u_int ef, u_int esp, 41339220Sgibbs u_int ss)); 41423925Sgibbsvoid setidt __P((int idx, alias_for_inthand_t *func, int typ, 41523925Sgibbs int dpl)); 41623925Sgibbs 41723925Sgibbs#endif /* !_MACHINE_CPUFUNC_H_ */ 41823925Sgibbs