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