00001 // See the end of this file for license information. 00002 00003 #ifndef TORSION_ASM_H 00004 #define TORSION_ASM_H 00005 00006 #include "types.h" 00007 00008 inline void 00009 enable_interrupts() { 00010 asm volatile("sti"); 00011 } 00012 00013 inline void 00014 disable_interrupts() { 00015 asm volatile("cli"); 00016 } 00017 00018 inline bool 00019 atomic_test_and_set(bool& target) { 00020 Uint8 result; 00021 00022 asm volatile("lock; bts $0, %1\n" 00023 "setc %0" 00024 : "=r" (result), "=m" (target)); 00025 00026 return result; 00027 } 00028 00029 inline unsigned long long 00030 system_cycles() { 00031 unsigned long time_high, time_low; 00032 00033 asm volatile("rdtsc" : "=d" (time_high), "=a" (time_low)); 00034 00035 return ((unsigned long long)time_high << 32) | time_low; 00036 } 00037 00038 inline unsigned 00039 system_milliseconds(unsigned cycles_per_millisecond) { 00040 unsigned total_seconds; 00041 00042 asm volatile("rdtsc\n" 00043 "divl %%ebx" 00044 : "=a" (total_seconds) 00045 : "b" (cycles_per_millisecond)); 00046 00047 return total_seconds; 00048 } 00049 00050 // thank you, Linux kernel! 00051 // all the functions/macros that we don't use currently are #if 0'd out 00052 00053 // send a byte out to a port 00054 inline void 00055 outb(unsigned short int value, unsigned port) { 00056 asm volatile("outb %%al, %%dx" : : "a" (value), "d" (port)); 00057 } 00058 00059 inline unsigned char 00060 inb(unsigned port) { 00061 unsigned char value; 00062 asm volatile("inb %%dx, %%al" : "=a" (value) : "d" (port)); 00063 return value; 00064 } 00065 00066 #if 0 00067 static inline char * strcpy(char * dest,const char *src) 00068 { 00069 int d0, d1, d2; 00070 __asm__ __volatile__( 00071 "1:\tlodsb\n\t" 00072 "stosb\n\t" 00073 "testb %%al,%%al\n\t" 00074 "jne 1b" 00075 : "=&S" (d0), "=&D" (d1), "=&a" (d2) 00076 :"0" (src),"1" (dest) : "memory"); 00077 return dest; 00078 } 00079 00080 static inline char * strncpy(char * dest,const char *src,Size count) 00081 { 00082 int d0, d1, d2, d3; 00083 __asm__ __volatile__( 00084 "1:\tdecl %2\n\t" 00085 "js 2f\n\t" 00086 "lodsb\n\t" 00087 "stosb\n\t" 00088 "testb %%al,%%al\n\t" 00089 "jne 1b\n\t" 00090 "rep\n\t" 00091 "stosb\n" 00092 "2:" 00093 : "=&S" (d0), "=&D" (d1), "=&c" (d2), "=&a" (d3) 00094 :"0" (src),"1" (dest),"2" (count) : "memory"); 00095 return dest; 00096 } 00097 00098 static inline char * strcat(char * dest,const char * src) 00099 { 00100 int d0, d1, d2, d3; 00101 __asm__ __volatile__( 00102 "repne\n\t" 00103 "scasb\n\t" 00104 "decl %1\n" 00105 "1:\tlodsb\n\t" 00106 "stosb\n\t" 00107 "testb %%al,%%al\n\t" 00108 "jne 1b" 00109 : "=&S" (d0), "=&D" (d1), "=&a" (d2), "=&c" (d3) 00110 : "0" (src), "1" (dest), "2" (0), "3" (0xffffffff):"memory"); 00111 return dest; 00112 } 00113 00114 static inline char * strncat(char * dest,const char * src,Size count) 00115 { 00116 int d0, d1, d2, d3; 00117 __asm__ __volatile__( 00118 "repne\n\t" 00119 "scasb\n\t" 00120 "decl %1\n\t" 00121 "movl %8,%3\n" 00122 "1:\tdecl %3\n\t" 00123 "js 2f\n\t" 00124 "lodsb\n\t" 00125 "stosb\n\t" 00126 "testb %%al,%%al\n\t" 00127 "jne 1b\n" 00128 "2:\txorl %2,%2\n\t" 00129 "stosb" 00130 : "=&S" (d0), "=&D" (d1), "=&a" (d2), "=&c" (d3) 00131 : "0" (src),"1" (dest),"2" (0),"3" (0xffffffff), "g" (count) 00132 : "memory"); 00133 return dest; 00134 } 00135 #endif 00136 00137 static inline int strcmp(const char * cs,const char * ct) 00138 { 00139 int d0, d1; 00140 register int __res; 00141 __asm__ __volatile__( 00142 "1:\tlodsb\n\t" 00143 "scasb\n\t" 00144 "jne 2f\n\t" 00145 "testb %%al,%%al\n\t" 00146 "jne 1b\n\t" 00147 "xorl %%eax,%%eax\n\t" 00148 "jmp 3f\n" 00149 "2:\tsbbl %%eax,%%eax\n\t" 00150 "orb $1,%%al\n" 00151 "3:" 00152 :"=a" (__res), "=&S" (d0), "=&D" (d1) 00153 :"1" (cs),"2" (ct)); 00154 return __res; 00155 } 00156 00157 static inline int strncmp(const char * cs,const char * ct,Size count) 00158 { 00159 register int __res; 00160 int d0, d1, d2; 00161 __asm__ __volatile__( 00162 "1:\tdecl %3\n\t" 00163 "js 2f\n\t" 00164 "lodsb\n\t" 00165 "scasb\n\t" 00166 "jne 3f\n\t" 00167 "testb %%al,%%al\n\t" 00168 "jne 1b\n" 00169 "2:\txorl %%eax,%%eax\n\t" 00170 "jmp 4f\n" 00171 "3:\tsbbl %%eax,%%eax\n\t" 00172 "orb $1,%%al\n" 00173 "4:" 00174 :"=a" (__res), "=&S" (d0), "=&D" (d1), "=&c" (d2) 00175 :"1" (cs),"2" (ct),"3" (count)); 00176 return __res; 00177 } 00178 00179 #if 0 00180 static inline char * strchr(const char * s, int c) 00181 { 00182 int d0; 00183 register char * __res; 00184 __asm__ __volatile__( 00185 "movb %%al,%%ah\n" 00186 "1:\tlodsb\n\t" 00187 "cmpb %%ah,%%al\n\t" 00188 "je 2f\n\t" 00189 "testb %%al,%%al\n\t" 00190 "jne 1b\n\t" 00191 "movl $1,%1\n" 00192 "2:\tmovl %1,%0\n\t" 00193 "decl %0" 00194 :"=a" (__res), "=&S" (d0) : "1" (s),"0" (c)); 00195 return __res; 00196 } 00197 00198 static inline char * strrchr(const char * s, int c) 00199 { 00200 int d0, d1; 00201 register char * __res; 00202 __asm__ __volatile__( 00203 "movb %%al,%%ah\n" 00204 "1:\tlodsb\n\t" 00205 "cmpb %%ah,%%al\n\t" 00206 "jne 2f\n\t" 00207 "leal -1(%%esi),%0\n" 00208 "2:\ttestb %%al,%%al\n\t" 00209 "jne 1b" 00210 :"=g" (__res), "=&S" (d0), "=&a" (d1) :"0" (0),"1" (s),"2" (c)); 00211 return __res; 00212 } 00213 #endif 00214 00215 static inline Size strlen(const char * s) 00216 { 00217 int d0; 00218 register int __res; 00219 __asm__ __volatile__( 00220 "repne\n\t" 00221 "scasb\n\t" 00222 "notl %0\n\t" 00223 "decl %0" 00224 :"=c" (__res), "=&D" (d0) :"1" (s),"a" (0), "0" (0xffffffff)); 00225 return __res; 00226 } 00227 00228 static inline void * __memcpy(void * to, const void * from, Size n) 00229 { 00230 int d0, d1, d2; 00231 __asm__ __volatile__( 00232 "rep ; movsl\n\t" 00233 "testb $2,%b4\n\t" 00234 "je 1f\n\t" 00235 "movsw\n" 00236 "1:\ttestb $1,%b4\n\t" 00237 "je 2f\n\t" 00238 "movsb\n" 00239 "2:" 00240 : "=&c" (d0), "=&D" (d1), "=&S" (d2) 00241 :"0" (n/4), "q" (n),"1" ((long) to),"2" ((long) from) 00242 : "memory"); 00243 return (to); 00244 } 00245 00246 /* 00247 * This looks horribly ugly, but the compiler can optimize it totally, 00248 * as the count is constant. 00249 */ 00250 static inline void * __constant_memcpy(void * to, const void * from, Size n) 00251 { 00252 switch (n) { 00253 case 0: 00254 return to; 00255 case 1: 00256 *(unsigned char *)to = *(const unsigned char *)from; 00257 return to; 00258 case 2: 00259 *(unsigned short *)to = *(const unsigned short *)from; 00260 return to; 00261 case 3: 00262 *(unsigned short *)to = *(const unsigned short *)from; 00263 *(2+(unsigned char *)to) = *(2+(const unsigned char *)from); 00264 return to; 00265 case 4: 00266 *(unsigned long *)to = *(const unsigned long *)from; 00267 return to; 00268 case 6: /* for Ethernet addresses */ 00269 *(unsigned long *)to = *(const unsigned long *)from; 00270 *(2+(unsigned short *)to) = *(2+(const unsigned short *)from); 00271 return to; 00272 case 8: 00273 *(unsigned long *)to = *(const unsigned long *)from; 00274 *(1+(unsigned long *)to) = *(1+(const unsigned long *)from); 00275 return to; 00276 case 12: 00277 *(unsigned long *)to = *(const unsigned long *)from; 00278 *(1+(unsigned long *)to) = *(1+(const unsigned long *)from); 00279 *(2+(unsigned long *)to) = *(2+(const unsigned long *)from); 00280 return to; 00281 case 16: 00282 *(unsigned long *)to = *(const unsigned long *)from; 00283 *(1+(unsigned long *)to) = *(1+(const unsigned long *)from); 00284 *(2+(unsigned long *)to) = *(2+(const unsigned long *)from); 00285 *(3+(unsigned long *)to) = *(3+(const unsigned long *)from); 00286 return to; 00287 case 20: 00288 *(unsigned long *)to = *(const unsigned long *)from; 00289 *(1+(unsigned long *)to) = *(1+(const unsigned long *)from); 00290 *(2+(unsigned long *)to) = *(2+(const unsigned long *)from); 00291 *(3+(unsigned long *)to) = *(3+(const unsigned long *)from); 00292 *(4+(unsigned long *)to) = *(4+(const unsigned long *)from); 00293 return to; 00294 } 00295 #define COMMON(x) \ 00296 __asm__ __volatile__( \ 00297 "rep ; movsl" \ 00298 x \ 00299 : "=&c" (d0), "=&D" (d1), "=&S" (d2) \ 00300 : "0" (n/4),"1" ((long) to),"2" ((long) from) \ 00301 : "memory"); 00302 { 00303 int d0, d1, d2; 00304 switch (n % 4) { 00305 case 0: COMMON(""); return to; 00306 case 1: COMMON("\n\tmovsb"); return to; 00307 case 2: COMMON("\n\tmovsw"); return to; 00308 default: COMMON("\n\tmovsw\n\tmovsb"); return to; 00309 } 00310 } 00311 00312 #undef COMMON 00313 } 00314 00315 #define memcpy(t, f, n) \ 00316 (__builtin_constant_p(n) ? \ 00317 __constant_memcpy((t),(f),(n)) : \ 00318 __memcpy((t),(f),(n))) 00319 00320 #if 0 00321 /* 00322 * struct_cpy(x,y), copy structure *x into (matching structure) *y. 00323 * 00324 * We get link-time errors if the structure sizes do not match. 00325 * There is no runtime overhead, it's all optimized away at 00326 * compile time. 00327 */ 00328 extern void __struct_cpy_bug (void); 00329 00330 #define struct_cpy(x,y) \ 00331 ({ \ 00332 if (sizeof(*(x)) != sizeof(*(y))) \ 00333 __struct_cpy_bug; \ 00334 memcpy(x, y, sizeof(*(x))); \ 00335 }) 00336 #endif 00337 00338 static inline void * memmove(void * dest,const void * src, Size n) 00339 { 00340 int d0, d1, d2; 00341 if (dest<src) 00342 __asm__ __volatile__( 00343 "rep\n\t" 00344 "movsb" 00345 : "=&c" (d0), "=&S" (d1), "=&D" (d2) 00346 :"0" (n),"1" (src),"2" (dest) 00347 : "memory"); 00348 else 00349 __asm__ __volatile__( 00350 "std\n\t" 00351 "rep\n\t" 00352 "movsb\n\t" 00353 "cld" 00354 : "=&c" (d0), "=&S" (d1), "=&D" (d2) 00355 :"0" (n), 00356 "1" (n-1+(const char *)src), 00357 "2" (n-1+(char *)dest) 00358 :"memory"); 00359 return dest; 00360 } 00361 00362 #if 0 00363 #define memcmp __builtin_memcmp 00364 00365 static inline void * memchr(const void * cs,int c,Size count) 00366 { 00367 int d0; 00368 register void * __res; 00369 if (!count) 00370 return NULL; 00371 __asm__ __volatile__( 00372 "repne\n\t" 00373 "scasb\n\t" 00374 "je 1f\n\t" 00375 "movl $1,%0\n" 00376 "1:\tdecl %0" 00377 :"=D" (__res), "=&c" (d0) : "a" (c),"0" (cs),"1" (count)); 00378 return __res; 00379 } 00380 #endif 00381 00382 static inline void * __memset_generic(void * s, char c,Size count) 00383 { 00384 int d0, d1; 00385 __asm__ __volatile__( 00386 "rep\n\t" 00387 "stosb" 00388 : "=&c" (d0), "=&D" (d1) 00389 :"a" (c),"1" (s),"0" (count) 00390 :"memory"); 00391 return s; 00392 } 00393 00394 /* we might want to write optimized versions of these later */ 00395 #define __constant_count_memset(s,c,count) __memset_generic((s),(c),(count)) 00396 00397 /* 00398 * memset(x,0,y) is a reasonably common thing to do, so we want to fill 00399 * things 32 bits at a time even when we don't know the size of the 00400 * area at compile-time.. 00401 */ 00402 static inline void * __constant_c_memset(void * s, unsigned long c, Size count) 00403 { 00404 int d0, d1; 00405 __asm__ __volatile__( 00406 "rep ; stosl\n\t" 00407 "testb $2,%b3\n\t" 00408 "je 1f\n\t" 00409 "stosw\n" 00410 "1:\ttestb $1,%b3\n\t" 00411 "je 2f\n\t" 00412 "stosb\n" 00413 "2:" 00414 : "=&c" (d0), "=&D" (d1) 00415 :"a" (c), "q" (count), "0" (count/4), "1" ((long) s) 00416 :"memory"); 00417 return (s); 00418 } 00419 00420 #if 0 00421 /* Added by Gertjan van Wingerde to make minix and sysv module work */ 00422 static inline Size strnlen(const char * s, Size count) 00423 { 00424 int d0; 00425 register int __res; 00426 __asm__ __volatile__( 00427 "movl %2,%0\n\t" 00428 "jmp 2f\n" 00429 "1:\tcmpb $0,(%0)\n\t" 00430 "je 3f\n\t" 00431 "incl %0\n" 00432 "2:\tdecl %1\n\t" 00433 "cmpl $-1,%1\n\t" 00434 "jne 1b\n" 00435 "3:\tsubl %2,%0" 00436 :"=a" (__res), "=&d" (d0) 00437 :"c" (s),"1" (count)); 00438 return __res; 00439 } 00440 /* end of additional stuff */ 00441 00442 extern char *strstr(const char *cs, const char *ct); 00443 #endif 00444 00445 /* 00446 * This looks horribly ugly, but the compiler can optimize it totally, 00447 * as we by now know that both pattern and count is constant.. 00448 */ 00449 static inline void * __constant_c_and_count_memset(void * s, unsigned long pattern, Size count) 00450 { 00451 switch (count) { 00452 case 0: 00453 return s; 00454 case 1: 00455 *(unsigned char *)s = pattern; 00456 return s; 00457 case 2: 00458 *(unsigned short *)s = pattern; 00459 return s; 00460 case 3: 00461 *(unsigned short *)s = pattern; 00462 *(2+(unsigned char *)s) = pattern; 00463 return s; 00464 case 4: 00465 *(unsigned long *)s = pattern; 00466 return s; 00467 } 00468 #define COMMON(x) \ 00469 __asm__ __volatile__( \ 00470 "rep ; stosl" \ 00471 x \ 00472 : "=&c" (d0), "=&D" (d1) \ 00473 : "a" (pattern),"0" (count/4),"1" ((long) s) \ 00474 : "memory") 00475 { 00476 int d0, d1; 00477 switch (count % 4) { 00478 case 0: COMMON(""); return s; 00479 case 1: COMMON("\n\tstosb"); return s; 00480 case 2: COMMON("\n\tstosw"); return s; 00481 default: COMMON("\n\tstosw\n\tstosb"); return s; 00482 } 00483 } 00484 00485 #undef COMMON 00486 } 00487 00488 #define __constant_c_x_memset(s, c, count) \ 00489 (__builtin_constant_p(count) ? \ 00490 __constant_c_and_count_memset((s),(c),(count)) : \ 00491 __constant_c_memset((s),(c),(count))) 00492 00493 #define __memset(s, c, count) \ 00494 (__builtin_constant_p(count) ? \ 00495 __constant_count_memset((s),(c),(count)) : \ 00496 __memset_generic((s),(c),(count))) 00497 00498 #define __HAVE_ARCH_MEMSET 00499 #define memset(s, c, count) \ 00500 (__builtin_constant_p(c) ? \ 00501 __constant_c_x_memset((s),(0x01010101UL*(unsigned char)(c)),(count)) : \ 00502 __memset((s),(c),(count))) 00503 00504 #if 0 00505 /* 00506 * find the first occurrence of byte 'c', or 1 past the area if none 00507 */ 00508 #define __HAVE_ARCH_MEMSCAN 00509 static inline void * memscan(void * addr, int c, Size size) 00510 { 00511 if (!size) 00512 return addr; 00513 __asm__("repnz; scasb\n\t" 00514 "jnz 1f\n\t" 00515 "dec %%edi\n" 00516 "1:" 00517 : "=D" (addr), "=c" (size) 00518 : "0" (addr), "1" (size), "a" (c)); 00519 return addr; 00520 } 00521 00528 static __inline__ unsigned long ffz(unsigned long word) 00529 { 00530 __asm__("bsfl %1,%0" 00531 :"=r" (word) 00532 :"r" (~word)); 00533 return word; 00534 } 00535 00544 static __inline__ int ffs(int x) 00545 { 00546 int r; 00547 00548 __asm__("bsfl %1,%0\n\t" 00549 "jnz 1f\n\t" 00550 "movl $-1,%0\n" 00551 "1:" : "=r" (r) : "g" (x)); 00552 return r+1; 00553 } 00554 #endif 00555 00556 #endif 00557 00558 /* Torsion Operating System, Copyright (C) 2000-2004 Dan Helfman 00559 * 00560 * This program is free software; you can redistribute it and/or modify it 00561 * under the terms of the GNU General Public License as published by the 00562 * Free Software Foundation; either version 2 of the License, or (at your 00563 * option) any later version. 00564 * 00565 * This program is distributed in the hope that it will be useful, but 00566 * WITHOUT ANY WARRANTY; without even the implied warranty of 00567 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00568 * General Public License for more details (in the COPYING file). 00569 * 00570 * You should have received a copy of the GNU General Public License along 00571 * with this program; if not, write to the Free Software Foundation, Inc., 00572 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 00573 */
Torsion Operating System, Copyright (C) 2000-2004 Dan Helfman