The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/i386/include/cpufunc.h

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    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  * 3. All advertising materials mentioning features or use of this software
   14  *    must display the following acknowledgement:
   15  *      This product includes software developed by the University of
   16  *      California, Berkeley and its contributors.
   17  * 4. Neither the name of the University nor the names of its contributors
   18  *    may be used to endorse or promote products derived from this software
   19  *    without specific prior written permission.
   20  *
   21  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
   22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
   25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   31  * SUCH DAMAGE.
   32  *
   33  * $FreeBSD: src/sys/i386/include/cpufunc.h,v 1.59.2.3 1999/09/05 08:11:44 peter Exp $
   34  */
   35 
   36 /*
   37  * Functions to provide access to special i386 instructions.
   38  */
   39 
   40 #ifndef _MACHINE_CPUFUNC_H_
   41 #define _MACHINE_CPUFUNC_H_
   42 
   43 #include <sys/cdefs.h>
   44 #include <sys/types.h>
   45 
   46 #ifdef  __GNUC__
   47 
   48 static __inline void
   49 breakpoint(void)
   50 {
   51         __asm __volatile("int $3");
   52 }
   53 
   54 static __inline void
   55 disable_intr(void)
   56 {
   57         __asm __volatile("cli" : : : "memory");
   58 }
   59 
   60 static __inline void
   61 enable_intr(void)
   62 {
   63         __asm __volatile("sti");
   64 }
   65 
   66 #define HAVE_INLINE_FFS
   67 
   68 static __inline int
   69 ffs(int mask)
   70 {
   71         int     result;
   72         /*
   73          * bsfl turns out to be not all that slow on 486's.  It can beaten
   74          * using a binary search to reduce to 4 bits and then a table lookup,
   75          * but only if the code is inlined and in the cache, and the code
   76          * is quite large so inlining it probably busts the cache.
   77          *
   78          * Note that gcc-2's builtin ffs would be used if we didn't declare
   79          * this inline or turn off the builtin.  The builtin is faster but
   80          * broken in gcc-2.4.5 and slower but working in gcc-2.5 and 2.6.
   81          */
   82         __asm __volatile("testl %0,%0; je 1f; bsfl %0,%0; incl %0; 1:"
   83                          : "=r" (result) : "" (mask));
   84         return (result);
   85 }
   86 
   87 #define HAVE_INLINE_FLS
   88 
   89 static __inline int
   90 fls(int mask)
   91 {
   92         int     result;
   93         __asm __volatile("testl %0,%0; je 1f; bsrl %0,%0; incl %0; 1:"
   94                          : "=r" (result) : "" (mask));
   95         return (result);
   96 }
   97 
   98 #if __GNUC__ < 2
   99 
  100 #define inb(port)               inbv(port)
  101 #define outb(port, data)        outbv(port, data)
  102 
  103 #else /* __GNUC >= 2 */
  104 
  105 /*
  106  * The following complications are to get around gcc not having a
  107  * constraint letter for the range 0..255.  We still put "d" in the
  108  * constraint because "i" isn't a valid constraint when the port
  109  * isn't constant.  This only matters for -O0 because otherwise
  110  * the non-working version gets optimized away.
  111  * 
  112  * Use an expression-statement instead of a conditional expression
  113  * because gcc-2.6.0 would promote the operands of the conditional
  114  * and produce poor code for "if ((inb(var) & const1) == const2)".
  115  *
  116  * The unnecessary test `(port) < 0x10000' is to generate a warning if
  117  * the `port' has type u_short or smaller.  Such types are pessimal.
  118  * This actually only works for signed types.  The range check is
  119  * careful to avoid generating warnings.
  120  */
  121 #define inb(port) __extension__ ({                                      \
  122         u_char  _data;                                                  \
  123         if (__builtin_constant_p(port) && ((port) & 0xffff) < 0x100     \
  124             && (port) < 0x10000)                                        \
  125                 _data = inbc(port);                                     \
  126         else                                                            \
  127                 _data = inbv(port);                                     \
  128         _data; })
  129 
  130 #define outb(port, data) (                                              \
  131         __builtin_constant_p(port) && ((port) & 0xffff) < 0x100         \
  132         && (port) < 0x10000                                             \
  133         ? outbc(port, data) : outbv(port, data))
  134 
  135 static __inline u_char
  136 inbc(u_int port)
  137 {
  138         u_char  data;
  139 
  140         __asm __volatile("inb %1,%0" : "=a" (data) : "id" ((u_short)(port)));
  141         return (data);
  142 }
  143 
  144 static __inline void
  145 outbc(u_int port, u_char data)
  146 {
  147         __asm __volatile("outb %0,%1" : : "a" (data), "id" ((u_short)(port)));
  148 }
  149 
  150 #endif /* __GNUC <= 2 */
  151 
  152 static __inline u_char
  153 inbv(u_int port)
  154 {
  155         u_char  data;
  156         /*
  157          * We use %%dx and not %1 here because i/o is done at %dx and not at
  158          * %edx, while gcc generates inferior code (movw instead of movl)
  159          * if we tell it to load (u_short) port.
  160          */
  161         __asm __volatile("inb %%dx,%0" : "=a" (data) : "d" (port));
  162         return (data);
  163 }
  164 
  165 static __inline u_long
  166 inl(u_int port)
  167 {
  168         u_long  data;
  169 
  170         __asm __volatile("inl %%dx,%0" : "=a" (data) : "d" (port));
  171         return (data);
  172 }
  173 
  174 static __inline void
  175 insb(u_int port, void *addr, size_t cnt)
  176 {
  177         __asm __volatile("cld; rep; insb"
  178                          : : "d" (port), "D" (addr), "c" (cnt)
  179                          : "di", "cx", "memory");
  180 }
  181 
  182 static __inline void
  183 insw(u_int port, void *addr, size_t cnt)
  184 {
  185         __asm __volatile("cld; rep; insw"
  186                          : : "d" (port), "D" (addr), "c" (cnt)
  187                          : "di", "cx", "memory");
  188 }
  189 
  190 static __inline void
  191 insl(u_int port, void *addr, size_t cnt)
  192 {
  193         __asm __volatile("cld; rep; insl"
  194                          : : "d" (port), "D" (addr), "c" (cnt)
  195                          : "di", "cx", "memory");
  196 }
  197 
  198 static __inline void
  199 invd(void)
  200 {
  201         __asm __volatile("invd");
  202 }
  203 
  204 static __inline void
  205 invlpg(u_int addr)
  206 {
  207         __asm __volatile("invlpg (%0)" : : "r" (addr) : "memory");
  208 }
  209 
  210 static __inline void
  211 invltlb(void)
  212 {
  213         u_long  temp;
  214         /*
  215          * This should be implemented as load_cr3(rcr3()) when load_cr3()
  216          * is inlined.
  217          */
  218         __asm __volatile("movl %%cr3, %0; movl %0, %%cr3" : "=r" (temp)
  219                          : : "memory");
  220 }
  221 
  222 static __inline u_short
  223 inw(u_int port)
  224 {
  225         u_short data;
  226 
  227         __asm __volatile("inw %%dx,%0" : "=a" (data) : "d" (port));
  228         return (data);
  229 }
  230 
  231 static __inline u_int
  232 loadandclear(u_int *addr)
  233 {
  234         u_int   result;
  235 
  236         __asm __volatile("xorl %0,%0; xchgl %1,%0"
  237                          : "=&r" (result) : "m" (*addr));
  238         return (result);
  239 }
  240 
  241 static __inline void
  242 outbv(u_int port, u_char data)
  243 {
  244         u_char  al;
  245         /*
  246          * Use an unnecessary assignment to help gcc's register allocator.
  247          * This make a large difference for gcc-1.40 and a tiny difference
  248          * for gcc-2.6.0.  For gcc-1.40, al had to be ``asm("ax")'' for
  249          * best results.  gcc-2.6.0 can't handle this.
  250          */
  251         al = data;
  252         __asm __volatile("outb %0,%%dx" : : "a" (al), "d" (port));
  253 }
  254 
  255 static __inline void
  256 outl(u_int port, u_long data)
  257 {
  258         /*
  259          * outl() and outw() aren't used much so we haven't looked at
  260          * possible micro-optimizations such as the unnecessary
  261          * assignment for them.
  262          */
  263         __asm __volatile("outl %0,%%dx" : : "a" (data), "d" (port));
  264 }
  265 
  266 static __inline void
  267 outsb(u_int port, const void *addr, size_t cnt)
  268 {
  269         __asm __volatile("cld; rep; outsb"
  270                          : : "d" (port), "S" (addr), "c" (cnt)
  271                          : "si", "cx");
  272 }
  273 
  274 static __inline void
  275 outsw(u_int port, const void *addr, size_t cnt)
  276 {
  277         __asm __volatile("cld; rep; outsw"
  278                          : : "d" (port), "S" (addr), "c" (cnt)
  279                          : "si", "cx");
  280 }
  281 
  282 static __inline void
  283 outsl(u_int port, const void *addr, size_t cnt)
  284 {
  285         __asm __volatile("cld; rep; outsl"
  286                          : : "d" (port), "S" (addr), "c" (cnt)
  287                          : "si", "cx");
  288 }
  289 
  290 static __inline void
  291 outw(u_int port, u_short data)
  292 {
  293         __asm __volatile("outw %0,%%dx" : : "a" (data), "d" (port));
  294 }
  295 
  296 static __inline u_long
  297 rcr2(void)
  298 {
  299         u_long  data;
  300 
  301         __asm __volatile("movl %%cr2,%0" : "=r" (data));
  302         return (data);
  303 }
  304 
  305 static __inline u_long
  306 read_eflags(void)
  307 {
  308         u_long  ef;
  309 
  310         __asm __volatile("pushfl; popl %0" : "=r" (ef));
  311         return (ef);
  312 }
  313 
  314 static __inline quad_t
  315 rdmsr(u_int msr)
  316 {
  317         quad_t rv;
  318 
  319         __asm __volatile(".byte 0x0f, 0x32" : "=A" (rv) : "c" (msr));
  320         return (rv);
  321 }
  322 
  323 static __inline quad_t
  324 rdpmc(u_int pmc)
  325 {
  326         quad_t rv;
  327 
  328         __asm __volatile(".byte 0x0f, 0x33" : "=A" (rv) : "c" (pmc));
  329         return (rv);
  330 }
  331 
  332 static __inline quad_t
  333 rdtsc(void)
  334 {
  335         quad_t rv;
  336 
  337         __asm __volatile(".byte 0x0f, 0x31" : "=A" (rv));
  338         return (rv);
  339 }
  340 
  341 static __inline void
  342 setbits(volatile unsigned *addr, u_int bits)
  343 {
  344         __asm __volatile("orl %1,%0" : "=m" (*addr) : "ir" (bits));
  345 }
  346 
  347 static __inline void
  348 wbinvd(void)
  349 {
  350         __asm __volatile("wbinvd");
  351 }
  352 
  353 static __inline void
  354 write_eflags(u_long ef)
  355 {
  356         __asm __volatile("pushl %0; popfl" : : "r" (ef));
  357 }
  358 
  359 static __inline void
  360 wrmsr(u_int msr, quad_t newval)
  361 {
  362         __asm __volatile(".byte 0x0f, 0x30" : : "A" (newval), "c" (msr));
  363 }
  364 
  365 #else /* !__GNUC__ */
  366 
  367 int     breakpoint      __P((void));
  368 void    disable_intr    __P((void));
  369 void    enable_intr     __P((void));
  370 u_char  inb             __P((u_int port));
  371 u_long  inl             __P((u_int port));
  372 void    insb            __P((u_int port, void *addr, size_t cnt));
  373 void    insl            __P((u_int port, void *addr, size_t cnt));
  374 void    insw            __P((u_int port, void *addr, size_t cnt));
  375 void    invd            __P((void));
  376 void    invlpg          __P((u_int addr));
  377 void    invltlb         __P((void));
  378 u_short inw             __P((u_int port));
  379 u_int   loadandclear    __P((u_int *addr));
  380 void    outb            __P((u_int port, u_char data));
  381 void    outl            __P((u_int port, u_long data));
  382 void    outsb           __P((u_int port, void *addr, size_t cnt));
  383 void    outsl           __P((u_int port, void *addr, size_t cnt));
  384 void    outsw           __P((u_int port, void *addr, size_t cnt));
  385 void    outw            __P((u_int port, u_short data));
  386 u_long  rcr2            __P((void));
  387 quad_t  rdmsr           __P((u_int msr));
  388 quad_t  rdpmc           __P((u_int pmc));
  389 quad_t  rdtsc           __P((void));
  390 u_long  read_eflags     __P((void));
  391 void    setbits         __P((volatile unsigned *addr, u_int bits));
  392 void    wbinvd          __P((void));
  393 void    write_eflags    __P((u_long ef));
  394 void    wrmsr           __P((u_int msr, quad_t newval));
  395 
  396 #endif  /* __GNUC__ */
  397 
  398 void    load_cr0        __P((u_long cr0));
  399 void    load_cr3        __P((u_long cr3));
  400 void    ltr             __P((u_short sel));
  401 u_int   rcr0            __P((void));
  402 u_long  rcr3            __P((void));
  403 
  404 #include <machine/spl.h>        /* XXX belongs elsewhere */
  405 
  406 #endif /* !_MACHINE_CPUFUNC_H_ */

Cache object: 9f1d700b7921aa1299419e8567208d39


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.