Main Page   Modules   Alphabetical List   Data Structures   File List   Data Fields   Globals   Related Pages  

i386.h

Go to the documentation of this file.
00001 /*!     \file include/arch/i386.h
00002  *      \brief Generic (IA-32) routines and headers
00003  *      \author Andrea Righi <drizzt@inwind.it>
00004  *      \date Last update: 2004-02-19
00005  *      \note Copyright (&copy;) 2003 Andrea Righi
00006  *
00007  *      This file contains the definition of a lot useful function for
00008  *      the x86 architecture.
00009  *      The greater part of them are in assembler...
00010  */
00011 
00012 #ifndef I386_H
00013 #define I386_H
00014 
00015 #include <const.h>
00016 
00017 /** \ingroup Kernel
00018  *  \defgroup Ki386Routines Generic (IA-32) Routines
00019  *  Some useful asm routines for the IA-32 architecture.
00020  *  @{
00021  */
00022 
00023 //! \brief
00024 //!     Read the timestamp counter from the model-specific register
00025 //!     and put it into two 32-bit registers.
00026 #define rdtsc(low, high) \
00027         __asm__ __volatile__( "rdtsc" : "=a"(low), "=d"(high) )
00028 
00029 //! \brief
00030 //!     Read the timestamp counter from the model-specific register
00031 //!     and put it into eax:edx registers. This is a 64-bit value.
00032 #define rdtscll(val) \
00033         __asm__ __volatile__( "rdtsc" : "=A"(val) )
00034 
00035 //! \brief
00036 //!     Force strict CPU ordering (required for all out-of-order
00037 //!     Intel CPUs to preserve the order of execution).
00038 static __inline__ void mb()
00039 {
00040         __asm__ __volatile__ ("lock; addl $0,0(%%esp)": : :"memory");
00041 }
00042 
00043 //! \brief
00044 //!     A macro equivalent to the function mb().
00045 #define wmb()   mb()
00046 
00047 //! \brief
00048 //!     A macro that returns current instruction pointer.
00049 #define get_eip() ({ void *eip; __asm__("movl $1f,%0\n1:" : "=g" (eip)); eip; })
00050 
00051 //! \brief
00052 //!     Enable all interrupts.
00053 static __inline__ void enable()
00054 {
00055         __asm__ ("sti" : : : "memory");
00056 }
00057 
00058 //! \brief
00059 //!     Disable all interrupts.
00060 static __inline__ void disable()
00061 {
00062         __asm__ __volatile__ ("cli" : : : "memory");
00063 }
00064 
00065 //! \brief
00066 //!     Get the IF (interrupt enable flag) value from the EFLAGS register.
00067 //! \return The interrupt enable flag (IF).
00068 static __inline__ dword GET_IF()
00069 {
00070         register uint32_t IF;
00071         __asm__ __volatile__ (
00072                 "pushfl                 \n"
00073                 "popl   %%eax           \n"
00074                 "shrl   $9, %%eax       \n"
00075                 "andl   $1, %%eax       \n" : "=a" (IF) : );
00076         __asm__ __volatile__("" : : : "eax");
00077         return( IF );
00078 }
00079 
00080 //! \brief
00081 //!     Set the IF (interrupt enable flag) value into the EFLAGS register.
00082 //! \param IF The interrupt flag:
00083 //!     \li \e 1 = ON
00084 //!     \li \e 0 = OFF
00085 static __inline__ void SET_IF(dword IF)
00086 {
00087         __asm__ __volatile__ (
00088                 "pushfl                 \n"
00089                 "popl   %%eax           \n"
00090                 "orl    $(1 << 9), %%eax\n"
00091                 "andl   %0, %%eax       \n"
00092                 "pushl  %%eax           \n"
00093                 "popfl                  \n" : : "d" ((IF & 0x01) << 9) );
00094         __asm__ __volatile__("" : : : "eax", "edx");
00095 }
00096 
00097 // --- inport#x --------------------------------------------------------//
00098 
00099 //! A macro equivalent to the inportb(word port) function.
00100 #define in      inportb
00101 //! A macro equivalent to the inportw(word port) function.
00102 #define in16    inportw
00103 //! A macro equivalent to the inportl(word port) function.
00104 #define in32    inportl
00105 
00106 //! \brief
00107 //!     Get a \c byte from an I/O port.
00108 //! \param port The I/O port.
00109 //! \return The value of the byte.
00110 static __inline__ byte inportb(word port)
00111 {
00112         // Get a byte from I/O port                                             //
00113         register uint8_t val;
00114         __asm__ __volatile__ ("inb %%dx, %%al" : "=a" (val) : "d" (port));
00115         return( val );
00116 }
00117 
00118 //! \brief
00119 //!     Get a \c word from an I/O port.
00120 //! \param port The I/O port.
00121 //! \return The value of the word.
00122 static __inline__ word inportw(word port)
00123 {
00124         register uint16_t val;
00125         __asm__ __volatile__ ("inw %%dx, %%ax" : "=a" (val) : "d" (port));
00126         return( val );
00127 }
00128 
00129 //! \brief
00130 //!     Get a \c dword from an I/O port.
00131 //! \param port The I/O port.
00132 //! \return The value of the double word.
00133 static __inline__ dword inportl(word port)
00134 {
00135         register uint32_t val;
00136         __asm__ __volatile__ ("inl %%dx, %%eax" : "=a" (val) : "d" (port));
00137         return( val );
00138 }
00139 
00140 // --- outport#x -------------------------------------------------------//
00141 
00142 //! A macro equivalent to the outportb(word port, byte val) function.
00143 #define out     outportb
00144 //! A macro equivalent to the outportw(word port, word val) function.
00145 #define out16   outportw
00146 //! A macro equivalent to the outportl(word port, dword val) function.
00147 #define out32   outportl
00148 
00149 //! \brief
00150 //!     Put a \c byte to an I/O port.
00151 //! \param port The I/O port.
00152 //! \param val The value you want to put.
00153 static __inline__ void outportb(word port, byte val)
00154 {
00155         __asm__ __volatile__ ("outb %%al, %%dx" : : "d" (port), "a" (val));
00156 }
00157 
00158 //! \brief
00159 //!     Put a \c word to an I/O port.
00160 //! \param port The I/O port.
00161 //! \param val The value you want to put.
00162 static __inline__ void outportw(word port, word val)
00163 {
00164         __asm__ __volatile__ ("outw %%ax, %%dx" : : "d" (port), "a" (val));
00165 }
00166 
00167 //! \brief
00168 //!     Put a \c dword to an I/O port.
00169 //! \param port The I/O port.
00170 //! \param val The value you want to put.
00171 static __inline__ void outportl(word port, dword val)
00172 {
00173         __asm__ __volatile__ ("outl %%eax, %%dx" : : "d" (port), "a" (val));
00174 }
00175 
00176 // --- ins* ------------------------------------------------------------//
00177 
00178 //! \brief
00179 //!     The string version of in().
00180 //! \param port The I/O port.
00181 //! \param addr A memory buffer where the values will be copied.
00182 //! \param count How many bytes we want to read from the port.
00183 /*!     Copy a sequence of \a count bytes to the buffer \a addr from
00184  *      the port \a port.
00185  */
00186 static inline void insb(unsigned short port, void * addr, unsigned long count)
00187 {
00188         __asm__ __volatile__ ("rep ; insb": "=D"(addr), "=c"(count) : "d"(port), "0"(addr), "1"(count));
00189 }
00190 
00191 //! \brief
00192 //!     The string version of in16().
00193 //! \param port The I/O port.
00194 //! \param addr A memory buffer where the values will be copied.
00195 //! \param count How many words we want to read from the port.
00196 /*!     Copy a sequence of \a count words to the buffer \a addr from
00197  *      the port \a port.
00198  */
00199 static inline void insw(unsigned short port, void * addr, unsigned long count)
00200 {
00201         __asm__ __volatile__ ("rep ; insw": "=D"(addr), "=c"(count) : "d"(port), "0"(addr), "1"(count));
00202 }
00203 
00204 //! \brief
00205 //!     The string version of in32().
00206 //! \param port The I/O port.
00207 //! \param addr A memory buffer where the values will be copied.
00208 //! \param count How many double words we want to read from the port.
00209 /*!     Copy a sequence of \a count double words to the buffer \a addr
00210  *      from the port \a port.
00211  */
00212 static inline void insl(unsigned short port, void * addr, unsigned long count)
00213 {
00214         __asm__ __volatile__ ("rep ; insl": "=D"(addr), "=c"(count) : "d"(port), "0"(addr), "1"(count));
00215 }
00216 
00217 //! A macro equivalent to the
00218 //! insb(unsigned short port, void * addr, unsigned long count) function.
00219 #define inportbm insb
00220 //! A macro equivalent to the
00221 //! insw(unsigned short port, void * addr, unsigned long count) function.
00222 #define inportwm insw
00223 //! A macro equivalent to the
00224 //! insl(unsigned short port, void * addr, unsigned long count) function.
00225 #define inportlm insl
00226 
00227 // --- outs* -----------------------------------------------------------//
00228 
00229 //! \brief
00230 //!     The string version of out().
00231 //! \param port The I/O port.
00232 //! \param addr A memory buffer that contains the values to be copied.
00233 //! \param count How many bytes we want to write to the port.
00234 /*!     Copy a sequence of \a count bytes to the port \a port
00235  *      from the buffer \a addr.
00236  */
00237 static inline void outsb(unsigned short port, void * addr, unsigned long count)
00238 {
00239         __asm__ __volatile__ ("rep ; outsb": "=S"(addr), "=c"(count) : "d"(port), "0"(addr), "1"(count));
00240 }
00241 
00242 //! \brief
00243 //!     The string version of out16().
00244 //! \param port The I/O port.
00245 //! \param addr A memory buffer that contains the values to be copied.
00246 //! \param count How many words we want to write to the port.
00247 /*!     Copy a sequence of \a count words to the port \a port
00248  *      from the buffer \a addr.
00249  */
00250 static inline void outsw(unsigned short port, void * addr, unsigned long count)
00251 {
00252         __asm__ __volatile__ ("rep ; outsw": "=S"(addr), "=c"(count) : "d"(port), "0"(addr), "1"(count));
00253 }
00254 
00255 //! \brief
00256 //!     The string version of out32().
00257 //! \param port The I/O port.
00258 //! \param addr A memory buffer that contains the values to be copied.
00259 //! \param count How many double words we want to write to the port.
00260 /*!     Copy a sequence of \a count double words to the port \a port
00261  *      from the buffer \a addr.
00262  */
00263 static inline void outsl(unsigned short port, void * addr, unsigned long count)
00264 {
00265         __asm__ __volatile__ ("rep ; outsl": "=S"(addr), "=c"(count) : "d"(port), "0"(addr), "1"(count));
00266 }
00267 
00268 //! A macro equivalent to the
00269 //! outsb(unsigned short port, void * addr, unsigned long count) function.
00270 #define outportbm outsb
00271 //! A macro equivalent to the
00272 //! outsw(unsigned short port, void * addr, unsigned long count) function.
00273 #define outportwm outsw
00274 //! A macro equivalent to the
00275 //! outsl(unsigned short port, void * addr, unsigned long count) function.
00276 #define outportlm outsl
00277 
00278 // --- CPUID -----------------------------------------------------------//
00279 
00280 //! \brief
00281 //!     Get the CPUID information.
00282 //! \param op The operation code to perform.
00283 //! \param eax EAX register value after the CPUID execution.
00284 //! \param ebx EBX register value after the CPUID execution.
00285 //! \param ecx ECX register value after the CPUID execution.
00286 //! \param edx EDX register value after the CPUID execution.
00287 //! \warning
00288 //!     Not all the Intel CPUs support the CPUID instruction!!!
00289 //!     Only some Intel486 family and subsequent Intel processors
00290 //!     provide this method for determinig the architecture flags.
00291 //!     Execution of CPUID on a processor that does not support this
00292 //!     instruction will result in an invalid opcode exception.
00293 //!     \n \n
00294 //!     To determine if it is possible to use this instruction we can
00295 //!     use bit 21 of the EFLAGS register. If software can change the
00296 //!     value of this flag, the CPUID instruction is executable.
00297 static __inline__ void cpuid(int op, int *eax, int *ebx, int *ecx, int *edx)
00298 {
00299         __asm__ __volatile__(
00300                 "cpuid"
00301                 :
00302                 "=a" (*eax),
00303                 "=b" (*ebx),
00304                 "=c" (*ecx),
00305                 "=d" (*edx)
00306                 :
00307                 "0" (op)
00308         );
00309         __asm__ __volatile__ ("" : : : "eax", "ebx", "ecx", "edx");
00310 }
00311 
00312 // ---Atomic operators -------------------------------------------------//
00313 
00314 //! The atomic variable structure.
00315 typedef struct atomic
00316 {
00317         volatile int counter;
00318 } atomic_t;
00319 
00320 //! \brief Set the atomic value of \p v to \p i (guaranteed only 24 bits)
00321 //! \param v The atomic variable.
00322 //! \param i The value to assign.
00323 #define atomic_set(v, i)        (((v)->counter) = (i))
00324 //! \brief Read the atomic value of \p v (guaranteed only 24 bits)
00325 //! \param v The atomic variable.
00326 #define atomic_read(v)          ((v)->counter)
00327 
00328 //! \brief Perform an atomic increment.
00329 //! \param v The atomic value to increment.
00330 //! \warning Guaranteed only 24 bits.
00331 static __inline__ void atomic_inc(atomic_t *v)
00332 {
00333         __asm__ __volatile__ (  "lock; incl %0"
00334                                 : "=m"(v->counter) : "m"(v->counter));
00335 }
00336 
00337 //! \brief Perform an atomic decrement.
00338 //! \param v The atomic value to decrement.
00339 //! \warning Guaranteed only 24 bits.
00340 static __inline__ void atomic_dec(atomic_t *v)
00341 {
00342         __asm__ __volatile__ (  "lock; decl %0"
00343                                 : "=m"(v->counter) : "m"(v->counter));
00344 }
00345 
00346 //! \brief Halt the system by disabling the CPU.
00347 //! \warning
00348 //!     This is truly the end. You have to reboot the system
00349 //!     after this...
00350 static __inline__ void halt()
00351 {
00352         __asm__ __volatile__ ("cli\n hlt");
00353 }
00354 
00355 // --- Debug operators ------------------------------------------------- //
00356 
00357 //! \brief Perform a breakpoint exeception.
00358 static __inline__ void breakpoint()
00359 {
00360         __asm__ __volatile__ ("int3" : : : "memory");
00361 }
00362 
00363 /** @} */ // end of Ki386Routines
00364 
00365 #endif

Generated on Fri Feb 20 15:32:15 2004 for Minirighi by doxygen1.2.18