18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Most of the string-functions are rather heavily hand-optimized, 48c2ecf20Sopenharmony_ci * see especially strsep,strstr,str[c]spn. They should work, but are not 58c2ecf20Sopenharmony_ci * very easy to understand. Everything is done entirely within the register 68c2ecf20Sopenharmony_ci * set, making the functions fast and clean. String instructions have been 78c2ecf20Sopenharmony_ci * used through-out, making for "slightly" unclear code :-) 88c2ecf20Sopenharmony_ci * 98c2ecf20Sopenharmony_ci * AK: On P4 and K7 using non string instruction implementations might be faster 108c2ecf20Sopenharmony_ci * for large memory blocks. But most of them are unlikely to be used on large 118c2ecf20Sopenharmony_ci * strings. 128c2ecf20Sopenharmony_ci */ 138c2ecf20Sopenharmony_ci 148c2ecf20Sopenharmony_ci#include <linux/string.h> 158c2ecf20Sopenharmony_ci#include <linux/export.h> 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_ci#ifdef __HAVE_ARCH_STRCPY 188c2ecf20Sopenharmony_cichar *strcpy(char *dest, const char *src) 198c2ecf20Sopenharmony_ci{ 208c2ecf20Sopenharmony_ci int d0, d1, d2; 218c2ecf20Sopenharmony_ci asm volatile("1:\tlodsb\n\t" 228c2ecf20Sopenharmony_ci "stosb\n\t" 238c2ecf20Sopenharmony_ci "testb %%al,%%al\n\t" 248c2ecf20Sopenharmony_ci "jne 1b" 258c2ecf20Sopenharmony_ci : "=&S" (d0), "=&D" (d1), "=&a" (d2) 268c2ecf20Sopenharmony_ci : "0" (src), "1" (dest) : "memory"); 278c2ecf20Sopenharmony_ci return dest; 288c2ecf20Sopenharmony_ci} 298c2ecf20Sopenharmony_ciEXPORT_SYMBOL(strcpy); 308c2ecf20Sopenharmony_ci#endif 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_ci#ifdef __HAVE_ARCH_STRNCPY 338c2ecf20Sopenharmony_cichar *strncpy(char *dest, const char *src, size_t count) 348c2ecf20Sopenharmony_ci{ 358c2ecf20Sopenharmony_ci int d0, d1, d2, d3; 368c2ecf20Sopenharmony_ci asm volatile("1:\tdecl %2\n\t" 378c2ecf20Sopenharmony_ci "js 2f\n\t" 388c2ecf20Sopenharmony_ci "lodsb\n\t" 398c2ecf20Sopenharmony_ci "stosb\n\t" 408c2ecf20Sopenharmony_ci "testb %%al,%%al\n\t" 418c2ecf20Sopenharmony_ci "jne 1b\n\t" 428c2ecf20Sopenharmony_ci "rep\n\t" 438c2ecf20Sopenharmony_ci "stosb\n" 448c2ecf20Sopenharmony_ci "2:" 458c2ecf20Sopenharmony_ci : "=&S" (d0), "=&D" (d1), "=&c" (d2), "=&a" (d3) 468c2ecf20Sopenharmony_ci : "0" (src), "1" (dest), "2" (count) : "memory"); 478c2ecf20Sopenharmony_ci return dest; 488c2ecf20Sopenharmony_ci} 498c2ecf20Sopenharmony_ciEXPORT_SYMBOL(strncpy); 508c2ecf20Sopenharmony_ci#endif 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_ci#ifdef __HAVE_ARCH_STRCAT 538c2ecf20Sopenharmony_cichar *strcat(char *dest, const char *src) 548c2ecf20Sopenharmony_ci{ 558c2ecf20Sopenharmony_ci int d0, d1, d2, d3; 568c2ecf20Sopenharmony_ci asm volatile("repne\n\t" 578c2ecf20Sopenharmony_ci "scasb\n\t" 588c2ecf20Sopenharmony_ci "decl %1\n" 598c2ecf20Sopenharmony_ci "1:\tlodsb\n\t" 608c2ecf20Sopenharmony_ci "stosb\n\t" 618c2ecf20Sopenharmony_ci "testb %%al,%%al\n\t" 628c2ecf20Sopenharmony_ci "jne 1b" 638c2ecf20Sopenharmony_ci : "=&S" (d0), "=&D" (d1), "=&a" (d2), "=&c" (d3) 648c2ecf20Sopenharmony_ci : "0" (src), "1" (dest), "2" (0), "3" (0xffffffffu) : "memory"); 658c2ecf20Sopenharmony_ci return dest; 668c2ecf20Sopenharmony_ci} 678c2ecf20Sopenharmony_ciEXPORT_SYMBOL(strcat); 688c2ecf20Sopenharmony_ci#endif 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_ci#ifdef __HAVE_ARCH_STRNCAT 718c2ecf20Sopenharmony_cichar *strncat(char *dest, const char *src, size_t count) 728c2ecf20Sopenharmony_ci{ 738c2ecf20Sopenharmony_ci int d0, d1, d2, d3; 748c2ecf20Sopenharmony_ci asm volatile("repne\n\t" 758c2ecf20Sopenharmony_ci "scasb\n\t" 768c2ecf20Sopenharmony_ci "decl %1\n\t" 778c2ecf20Sopenharmony_ci "movl %8,%3\n" 788c2ecf20Sopenharmony_ci "1:\tdecl %3\n\t" 798c2ecf20Sopenharmony_ci "js 2f\n\t" 808c2ecf20Sopenharmony_ci "lodsb\n\t" 818c2ecf20Sopenharmony_ci "stosb\n\t" 828c2ecf20Sopenharmony_ci "testb %%al,%%al\n\t" 838c2ecf20Sopenharmony_ci "jne 1b\n" 848c2ecf20Sopenharmony_ci "2:\txorl %2,%2\n\t" 858c2ecf20Sopenharmony_ci "stosb" 868c2ecf20Sopenharmony_ci : "=&S" (d0), "=&D" (d1), "=&a" (d2), "=&c" (d3) 878c2ecf20Sopenharmony_ci : "0" (src), "1" (dest), "2" (0), "3" (0xffffffffu), "g" (count) 888c2ecf20Sopenharmony_ci : "memory"); 898c2ecf20Sopenharmony_ci return dest; 908c2ecf20Sopenharmony_ci} 918c2ecf20Sopenharmony_ciEXPORT_SYMBOL(strncat); 928c2ecf20Sopenharmony_ci#endif 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_ci#ifdef __HAVE_ARCH_STRCMP 958c2ecf20Sopenharmony_ciint strcmp(const char *cs, const char *ct) 968c2ecf20Sopenharmony_ci{ 978c2ecf20Sopenharmony_ci int d0, d1; 988c2ecf20Sopenharmony_ci int res; 998c2ecf20Sopenharmony_ci asm volatile("1:\tlodsb\n\t" 1008c2ecf20Sopenharmony_ci "scasb\n\t" 1018c2ecf20Sopenharmony_ci "jne 2f\n\t" 1028c2ecf20Sopenharmony_ci "testb %%al,%%al\n\t" 1038c2ecf20Sopenharmony_ci "jne 1b\n\t" 1048c2ecf20Sopenharmony_ci "xorl %%eax,%%eax\n\t" 1058c2ecf20Sopenharmony_ci "jmp 3f\n" 1068c2ecf20Sopenharmony_ci "2:\tsbbl %%eax,%%eax\n\t" 1078c2ecf20Sopenharmony_ci "orb $1,%%al\n" 1088c2ecf20Sopenharmony_ci "3:" 1098c2ecf20Sopenharmony_ci : "=a" (res), "=&S" (d0), "=&D" (d1) 1108c2ecf20Sopenharmony_ci : "1" (cs), "2" (ct) 1118c2ecf20Sopenharmony_ci : "memory"); 1128c2ecf20Sopenharmony_ci return res; 1138c2ecf20Sopenharmony_ci} 1148c2ecf20Sopenharmony_ciEXPORT_SYMBOL(strcmp); 1158c2ecf20Sopenharmony_ci#endif 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_ci#ifdef __HAVE_ARCH_STRNCMP 1188c2ecf20Sopenharmony_ciint strncmp(const char *cs, const char *ct, size_t count) 1198c2ecf20Sopenharmony_ci{ 1208c2ecf20Sopenharmony_ci int res; 1218c2ecf20Sopenharmony_ci int d0, d1, d2; 1228c2ecf20Sopenharmony_ci asm volatile("1:\tdecl %3\n\t" 1238c2ecf20Sopenharmony_ci "js 2f\n\t" 1248c2ecf20Sopenharmony_ci "lodsb\n\t" 1258c2ecf20Sopenharmony_ci "scasb\n\t" 1268c2ecf20Sopenharmony_ci "jne 3f\n\t" 1278c2ecf20Sopenharmony_ci "testb %%al,%%al\n\t" 1288c2ecf20Sopenharmony_ci "jne 1b\n" 1298c2ecf20Sopenharmony_ci "2:\txorl %%eax,%%eax\n\t" 1308c2ecf20Sopenharmony_ci "jmp 4f\n" 1318c2ecf20Sopenharmony_ci "3:\tsbbl %%eax,%%eax\n\t" 1328c2ecf20Sopenharmony_ci "orb $1,%%al\n" 1338c2ecf20Sopenharmony_ci "4:" 1348c2ecf20Sopenharmony_ci : "=a" (res), "=&S" (d0), "=&D" (d1), "=&c" (d2) 1358c2ecf20Sopenharmony_ci : "1" (cs), "2" (ct), "3" (count) 1368c2ecf20Sopenharmony_ci : "memory"); 1378c2ecf20Sopenharmony_ci return res; 1388c2ecf20Sopenharmony_ci} 1398c2ecf20Sopenharmony_ciEXPORT_SYMBOL(strncmp); 1408c2ecf20Sopenharmony_ci#endif 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_ci#ifdef __HAVE_ARCH_STRCHR 1438c2ecf20Sopenharmony_cichar *strchr(const char *s, int c) 1448c2ecf20Sopenharmony_ci{ 1458c2ecf20Sopenharmony_ci int d0; 1468c2ecf20Sopenharmony_ci char *res; 1478c2ecf20Sopenharmony_ci asm volatile("movb %%al,%%ah\n" 1488c2ecf20Sopenharmony_ci "1:\tlodsb\n\t" 1498c2ecf20Sopenharmony_ci "cmpb %%ah,%%al\n\t" 1508c2ecf20Sopenharmony_ci "je 2f\n\t" 1518c2ecf20Sopenharmony_ci "testb %%al,%%al\n\t" 1528c2ecf20Sopenharmony_ci "jne 1b\n\t" 1538c2ecf20Sopenharmony_ci "movl $1,%1\n" 1548c2ecf20Sopenharmony_ci "2:\tmovl %1,%0\n\t" 1558c2ecf20Sopenharmony_ci "decl %0" 1568c2ecf20Sopenharmony_ci : "=a" (res), "=&S" (d0) 1578c2ecf20Sopenharmony_ci : "1" (s), "0" (c) 1588c2ecf20Sopenharmony_ci : "memory"); 1598c2ecf20Sopenharmony_ci return res; 1608c2ecf20Sopenharmony_ci} 1618c2ecf20Sopenharmony_ciEXPORT_SYMBOL(strchr); 1628c2ecf20Sopenharmony_ci#endif 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_ci#ifdef __HAVE_ARCH_STRLEN 1658c2ecf20Sopenharmony_cisize_t strlen(const char *s) 1668c2ecf20Sopenharmony_ci{ 1678c2ecf20Sopenharmony_ci int d0; 1688c2ecf20Sopenharmony_ci size_t res; 1698c2ecf20Sopenharmony_ci asm volatile("repne\n\t" 1708c2ecf20Sopenharmony_ci "scasb" 1718c2ecf20Sopenharmony_ci : "=c" (res), "=&D" (d0) 1728c2ecf20Sopenharmony_ci : "1" (s), "a" (0), "0" (0xffffffffu) 1738c2ecf20Sopenharmony_ci : "memory"); 1748c2ecf20Sopenharmony_ci return ~res - 1; 1758c2ecf20Sopenharmony_ci} 1768c2ecf20Sopenharmony_ciEXPORT_SYMBOL(strlen); 1778c2ecf20Sopenharmony_ci#endif 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_ci#ifdef __HAVE_ARCH_MEMCHR 1808c2ecf20Sopenharmony_civoid *memchr(const void *cs, int c, size_t count) 1818c2ecf20Sopenharmony_ci{ 1828c2ecf20Sopenharmony_ci int d0; 1838c2ecf20Sopenharmony_ci void *res; 1848c2ecf20Sopenharmony_ci if (!count) 1858c2ecf20Sopenharmony_ci return NULL; 1868c2ecf20Sopenharmony_ci asm volatile("repne\n\t" 1878c2ecf20Sopenharmony_ci "scasb\n\t" 1888c2ecf20Sopenharmony_ci "je 1f\n\t" 1898c2ecf20Sopenharmony_ci "movl $1,%0\n" 1908c2ecf20Sopenharmony_ci "1:\tdecl %0" 1918c2ecf20Sopenharmony_ci : "=D" (res), "=&c" (d0) 1928c2ecf20Sopenharmony_ci : "a" (c), "0" (cs), "1" (count) 1938c2ecf20Sopenharmony_ci : "memory"); 1948c2ecf20Sopenharmony_ci return res; 1958c2ecf20Sopenharmony_ci} 1968c2ecf20Sopenharmony_ciEXPORT_SYMBOL(memchr); 1978c2ecf20Sopenharmony_ci#endif 1988c2ecf20Sopenharmony_ci 1998c2ecf20Sopenharmony_ci#ifdef __HAVE_ARCH_MEMSCAN 2008c2ecf20Sopenharmony_civoid *memscan(void *addr, int c, size_t size) 2018c2ecf20Sopenharmony_ci{ 2028c2ecf20Sopenharmony_ci if (!size) 2038c2ecf20Sopenharmony_ci return addr; 2048c2ecf20Sopenharmony_ci asm volatile("repnz; scasb\n\t" 2058c2ecf20Sopenharmony_ci "jnz 1f\n\t" 2068c2ecf20Sopenharmony_ci "dec %%edi\n" 2078c2ecf20Sopenharmony_ci "1:" 2088c2ecf20Sopenharmony_ci : "=D" (addr), "=c" (size) 2098c2ecf20Sopenharmony_ci : "0" (addr), "1" (size), "a" (c) 2108c2ecf20Sopenharmony_ci : "memory"); 2118c2ecf20Sopenharmony_ci return addr; 2128c2ecf20Sopenharmony_ci} 2138c2ecf20Sopenharmony_ciEXPORT_SYMBOL(memscan); 2148c2ecf20Sopenharmony_ci#endif 2158c2ecf20Sopenharmony_ci 2168c2ecf20Sopenharmony_ci#ifdef __HAVE_ARCH_STRNLEN 2178c2ecf20Sopenharmony_cisize_t strnlen(const char *s, size_t count) 2188c2ecf20Sopenharmony_ci{ 2198c2ecf20Sopenharmony_ci int d0; 2208c2ecf20Sopenharmony_ci int res; 2218c2ecf20Sopenharmony_ci asm volatile("movl %2,%0\n\t" 2228c2ecf20Sopenharmony_ci "jmp 2f\n" 2238c2ecf20Sopenharmony_ci "1:\tcmpb $0,(%0)\n\t" 2248c2ecf20Sopenharmony_ci "je 3f\n\t" 2258c2ecf20Sopenharmony_ci "incl %0\n" 2268c2ecf20Sopenharmony_ci "2:\tdecl %1\n\t" 2278c2ecf20Sopenharmony_ci "cmpl $-1,%1\n\t" 2288c2ecf20Sopenharmony_ci "jne 1b\n" 2298c2ecf20Sopenharmony_ci "3:\tsubl %2,%0" 2308c2ecf20Sopenharmony_ci : "=a" (res), "=&d" (d0) 2318c2ecf20Sopenharmony_ci : "c" (s), "1" (count) 2328c2ecf20Sopenharmony_ci : "memory"); 2338c2ecf20Sopenharmony_ci return res; 2348c2ecf20Sopenharmony_ci} 2358c2ecf20Sopenharmony_ciEXPORT_SYMBOL(strnlen); 2368c2ecf20Sopenharmony_ci#endif 237