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 (©) 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