11da177e4SLinus Torvalds /* 21da177e4SLinus Torvalds * arch/s390/lib/string.c 31da177e4SLinus Torvalds * Optimized string functions 41da177e4SLinus Torvalds * 51da177e4SLinus Torvalds * S390 version 61da177e4SLinus Torvalds * Copyright (C) 2004 IBM Deutschland Entwicklung GmbH, IBM Corporation 71da177e4SLinus Torvalds * Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com) 81da177e4SLinus Torvalds */ 91da177e4SLinus Torvalds 101da177e4SLinus Torvalds #define IN_ARCH_STRING_C 1 111da177e4SLinus Torvalds 121da177e4SLinus Torvalds #include <linux/types.h> 131da177e4SLinus Torvalds #include <linux/module.h> 141da177e4SLinus Torvalds 151da177e4SLinus Torvalds /* 161da177e4SLinus Torvalds * Helper functions to find the end of a string 171da177e4SLinus Torvalds */ 181da177e4SLinus Torvalds static inline char *__strend(const char *s) 191da177e4SLinus Torvalds { 201da177e4SLinus Torvalds register unsigned long r0 asm("0") = 0; 211da177e4SLinus Torvalds 221da177e4SLinus Torvalds asm volatile ("0: srst %0,%1\n" 231da177e4SLinus Torvalds " jo 0b" 241da177e4SLinus Torvalds : "+d" (r0), "+a" (s) : : "cc" ); 251da177e4SLinus Torvalds return (char *) r0; 261da177e4SLinus Torvalds } 271da177e4SLinus Torvalds 281da177e4SLinus Torvalds static inline char *__strnend(const char *s, size_t n) 291da177e4SLinus Torvalds { 301da177e4SLinus Torvalds register unsigned long r0 asm("0") = 0; 311da177e4SLinus Torvalds const char *p = s + n; 321da177e4SLinus Torvalds 331da177e4SLinus Torvalds asm volatile ("0: srst %0,%1\n" 341da177e4SLinus Torvalds " jo 0b" 351da177e4SLinus Torvalds : "+d" (p), "+a" (s) : "d" (r0) : "cc" ); 361da177e4SLinus Torvalds return (char *) p; 371da177e4SLinus Torvalds } 381da177e4SLinus Torvalds 391da177e4SLinus Torvalds /** 401da177e4SLinus Torvalds * strlen - Find the length of a string 411da177e4SLinus Torvalds * @s: The string to be sized 421da177e4SLinus Torvalds * 431da177e4SLinus Torvalds * returns the length of @s 441da177e4SLinus Torvalds */ 451da177e4SLinus Torvalds size_t strlen(const char *s) 461da177e4SLinus Torvalds { 471da177e4SLinus Torvalds return __strend(s) - s; 481da177e4SLinus Torvalds } 491da177e4SLinus Torvalds EXPORT_SYMBOL(strlen); 501da177e4SLinus Torvalds 511da177e4SLinus Torvalds /** 521da177e4SLinus Torvalds * strnlen - Find the length of a length-limited string 531da177e4SLinus Torvalds * @s: The string to be sized 541da177e4SLinus Torvalds * @n: The maximum number of bytes to search 551da177e4SLinus Torvalds * 561da177e4SLinus Torvalds * returns the minimum of the length of @s and @n 571da177e4SLinus Torvalds */ 581da177e4SLinus Torvalds size_t strnlen(const char * s, size_t n) 591da177e4SLinus Torvalds { 601da177e4SLinus Torvalds return __strnend(s, n) - s; 611da177e4SLinus Torvalds } 621da177e4SLinus Torvalds EXPORT_SYMBOL(strnlen); 631da177e4SLinus Torvalds 641da177e4SLinus Torvalds /** 651da177e4SLinus Torvalds * strcpy - Copy a %NUL terminated string 661da177e4SLinus Torvalds * @dest: Where to copy the string to 671da177e4SLinus Torvalds * @src: Where to copy the string from 681da177e4SLinus Torvalds * 691da177e4SLinus Torvalds * returns a pointer to @dest 701da177e4SLinus Torvalds */ 711da177e4SLinus Torvalds char *strcpy(char *dest, const char *src) 721da177e4SLinus Torvalds { 731da177e4SLinus Torvalds register int r0 asm("0") = 0; 741da177e4SLinus Torvalds char *ret = dest; 751da177e4SLinus Torvalds 761da177e4SLinus Torvalds asm volatile ("0: mvst %0,%1\n" 771da177e4SLinus Torvalds " jo 0b" 781da177e4SLinus Torvalds : "+&a" (dest), "+&a" (src) : "d" (r0) 791da177e4SLinus Torvalds : "cc", "memory" ); 801da177e4SLinus Torvalds return ret; 811da177e4SLinus Torvalds } 821da177e4SLinus Torvalds EXPORT_SYMBOL(strcpy); 831da177e4SLinus Torvalds 841da177e4SLinus Torvalds /** 851da177e4SLinus Torvalds * strlcpy - Copy a %NUL terminated string into a sized buffer 861da177e4SLinus Torvalds * @dest: Where to copy the string to 871da177e4SLinus Torvalds * @src: Where to copy the string from 881da177e4SLinus Torvalds * @size: size of destination buffer 891da177e4SLinus Torvalds * 901da177e4SLinus Torvalds * Compatible with *BSD: the result is always a valid 911da177e4SLinus Torvalds * NUL-terminated string that fits in the buffer (unless, 921da177e4SLinus Torvalds * of course, the buffer size is zero). It does not pad 931da177e4SLinus Torvalds * out the result like strncpy() does. 941da177e4SLinus Torvalds */ 951da177e4SLinus Torvalds size_t strlcpy(char *dest, const char *src, size_t size) 961da177e4SLinus Torvalds { 971da177e4SLinus Torvalds size_t ret = __strend(src) - src; 981da177e4SLinus Torvalds 991da177e4SLinus Torvalds if (size) { 1001da177e4SLinus Torvalds size_t len = (ret >= size) ? size-1 : ret; 1011da177e4SLinus Torvalds dest[len] = '\0'; 1021da177e4SLinus Torvalds __builtin_memcpy(dest, src, len); 1031da177e4SLinus Torvalds } 1041da177e4SLinus Torvalds return ret; 1051da177e4SLinus Torvalds } 1061da177e4SLinus Torvalds EXPORT_SYMBOL(strlcpy); 1071da177e4SLinus Torvalds 1081da177e4SLinus Torvalds /** 1091da177e4SLinus Torvalds * strncpy - Copy a length-limited, %NUL-terminated string 1101da177e4SLinus Torvalds * @dest: Where to copy the string to 1111da177e4SLinus Torvalds * @src: Where to copy the string from 1121da177e4SLinus Torvalds * @n: The maximum number of bytes to copy 1131da177e4SLinus Torvalds * 1141da177e4SLinus Torvalds * The result is not %NUL-terminated if the source exceeds 1151da177e4SLinus Torvalds * @n bytes. 1161da177e4SLinus Torvalds */ 1171da177e4SLinus Torvalds char *strncpy(char *dest, const char *src, size_t n) 1181da177e4SLinus Torvalds { 1191da177e4SLinus Torvalds size_t len = __strnend(src, n) - src; 1201da177e4SLinus Torvalds __builtin_memset(dest + len, 0, n - len); 1211da177e4SLinus Torvalds __builtin_memcpy(dest, src, len); 1221da177e4SLinus Torvalds return dest; 1231da177e4SLinus Torvalds } 1241da177e4SLinus Torvalds EXPORT_SYMBOL(strncpy); 1251da177e4SLinus Torvalds 1261da177e4SLinus Torvalds /** 1271da177e4SLinus Torvalds * strcat - Append one %NUL-terminated string to another 1281da177e4SLinus Torvalds * @dest: The string to be appended to 1291da177e4SLinus Torvalds * @src: The string to append to it 1301da177e4SLinus Torvalds * 1311da177e4SLinus Torvalds * returns a pointer to @dest 1321da177e4SLinus Torvalds */ 1331da177e4SLinus Torvalds char *strcat(char *dest, const char *src) 1341da177e4SLinus Torvalds { 1351da177e4SLinus Torvalds register int r0 asm("0") = 0; 1361da177e4SLinus Torvalds unsigned long dummy; 1371da177e4SLinus Torvalds char *ret = dest; 1381da177e4SLinus Torvalds 1391da177e4SLinus Torvalds asm volatile ("0: srst %0,%1\n" 1401da177e4SLinus Torvalds " jo 0b\n" 1411da177e4SLinus Torvalds "1: mvst %0,%2\n" 1421da177e4SLinus Torvalds " jo 1b" 1431da177e4SLinus Torvalds : "=&a" (dummy), "+a" (dest), "+a" (src) 1441da177e4SLinus Torvalds : "d" (r0), "0" (0UL) : "cc", "memory" ); 1451da177e4SLinus Torvalds return ret; 1461da177e4SLinus Torvalds } 1471da177e4SLinus Torvalds EXPORT_SYMBOL(strcat); 1481da177e4SLinus Torvalds 1491da177e4SLinus Torvalds /** 1501da177e4SLinus Torvalds * strlcat - Append a length-limited, %NUL-terminated string to another 1511da177e4SLinus Torvalds * @dest: The string to be appended to 1521da177e4SLinus Torvalds * @src: The string to append to it 1531da177e4SLinus Torvalds * @n: The size of the destination buffer. 1541da177e4SLinus Torvalds */ 1551da177e4SLinus Torvalds size_t strlcat(char *dest, const char *src, size_t n) 1561da177e4SLinus Torvalds { 1571da177e4SLinus Torvalds size_t dsize = __strend(dest) - dest; 1581da177e4SLinus Torvalds size_t len = __strend(src) - src; 1591da177e4SLinus Torvalds size_t res = dsize + len; 1601da177e4SLinus Torvalds 1611da177e4SLinus Torvalds if (dsize < n) { 1621da177e4SLinus Torvalds dest += dsize; 1631da177e4SLinus Torvalds n -= dsize; 1641da177e4SLinus Torvalds if (len >= n) 1651da177e4SLinus Torvalds len = n - 1; 1661da177e4SLinus Torvalds dest[len] = '\0'; 1671da177e4SLinus Torvalds __builtin_memcpy(dest, src, len); 1681da177e4SLinus Torvalds } 1691da177e4SLinus Torvalds return res; 1701da177e4SLinus Torvalds } 1711da177e4SLinus Torvalds EXPORT_SYMBOL(strlcat); 1721da177e4SLinus Torvalds 1731da177e4SLinus Torvalds /** 1741da177e4SLinus Torvalds * strncat - Append a length-limited, %NUL-terminated string to another 1751da177e4SLinus Torvalds * @dest: The string to be appended to 1761da177e4SLinus Torvalds * @src: The string to append to it 1771da177e4SLinus Torvalds * @n: The maximum numbers of bytes to copy 1781da177e4SLinus Torvalds * 1791da177e4SLinus Torvalds * returns a pointer to @dest 1801da177e4SLinus Torvalds * 1811da177e4SLinus Torvalds * Note that in contrast to strncpy, strncat ensures the result is 1821da177e4SLinus Torvalds * terminated. 1831da177e4SLinus Torvalds */ 1841da177e4SLinus Torvalds char *strncat(char *dest, const char *src, size_t n) 1851da177e4SLinus Torvalds { 1861da177e4SLinus Torvalds size_t len = __strnend(src, n) - src; 1871da177e4SLinus Torvalds char *p = __strend(dest); 1881da177e4SLinus Torvalds 1891da177e4SLinus Torvalds p[len] = '\0'; 1901da177e4SLinus Torvalds __builtin_memcpy(p, src, len); 1911da177e4SLinus Torvalds return dest; 1921da177e4SLinus Torvalds } 1931da177e4SLinus Torvalds EXPORT_SYMBOL(strncat); 1941da177e4SLinus Torvalds 1951da177e4SLinus Torvalds /** 1961da177e4SLinus Torvalds * strcmp - Compare two strings 1971da177e4SLinus Torvalds * @cs: One string 1981da177e4SLinus Torvalds * @ct: Another string 1991da177e4SLinus Torvalds * 2001da177e4SLinus Torvalds * returns 0 if @cs and @ct are equal, 2011da177e4SLinus Torvalds * < 0 if @cs is less than @ct 2021da177e4SLinus Torvalds * > 0 if @cs is greater than @ct 2031da177e4SLinus Torvalds */ 2041da177e4SLinus Torvalds int strcmp(const char *cs, const char *ct) 2051da177e4SLinus Torvalds { 2061da177e4SLinus Torvalds register int r0 asm("0") = 0; 2071da177e4SLinus Torvalds int ret = 0; 2081da177e4SLinus Torvalds 2091da177e4SLinus Torvalds asm volatile ("0: clst %2,%3\n" 2101da177e4SLinus Torvalds " jo 0b\n" 2111da177e4SLinus Torvalds " je 1f\n" 2121da177e4SLinus Torvalds " ic %0,0(%2)\n" 2131da177e4SLinus Torvalds " ic %1,0(%3)\n" 2141da177e4SLinus Torvalds " sr %0,%1\n" 2151da177e4SLinus Torvalds "1:" 2161da177e4SLinus Torvalds : "+d" (ret), "+d" (r0), "+a" (cs), "+a" (ct) 2171da177e4SLinus Torvalds : : "cc" ); 2181da177e4SLinus Torvalds return ret; 2191da177e4SLinus Torvalds } 2201da177e4SLinus Torvalds EXPORT_SYMBOL(strcmp); 2211da177e4SLinus Torvalds 2221da177e4SLinus Torvalds /** 2231da177e4SLinus Torvalds * strrchr - Find the last occurrence of a character in a string 2241da177e4SLinus Torvalds * @s: The string to be searched 2251da177e4SLinus Torvalds * @c: The character to search for 2261da177e4SLinus Torvalds */ 2271da177e4SLinus Torvalds char * strrchr(const char * s, int c) 2281da177e4SLinus Torvalds { 2291da177e4SLinus Torvalds size_t len = __strend(s) - s; 2301da177e4SLinus Torvalds 2311da177e4SLinus Torvalds if (len) 2321da177e4SLinus Torvalds do { 2331da177e4SLinus Torvalds if (s[len] == (char) c) 2341da177e4SLinus Torvalds return (char *) s + len; 2351da177e4SLinus Torvalds } while (--len > 0); 236*d2c993d8SHeiko Carstens return NULL; 2371da177e4SLinus Torvalds } 2381da177e4SLinus Torvalds EXPORT_SYMBOL(strrchr); 2391da177e4SLinus Torvalds 2401da177e4SLinus Torvalds /** 2411da177e4SLinus Torvalds * strstr - Find the first substring in a %NUL terminated string 2421da177e4SLinus Torvalds * @s1: The string to be searched 2431da177e4SLinus Torvalds * @s2: The string to search for 2441da177e4SLinus Torvalds */ 2451da177e4SLinus Torvalds char * strstr(const char * s1,const char * s2) 2461da177e4SLinus Torvalds { 2471da177e4SLinus Torvalds int l1, l2; 2481da177e4SLinus Torvalds 2491da177e4SLinus Torvalds l2 = __strend(s2) - s2; 2501da177e4SLinus Torvalds if (!l2) 2511da177e4SLinus Torvalds return (char *) s1; 2521da177e4SLinus Torvalds l1 = __strend(s1) - s1; 2531da177e4SLinus Torvalds while (l1-- >= l2) { 2541da177e4SLinus Torvalds register unsigned long r2 asm("2") = (unsigned long) s1; 2551da177e4SLinus Torvalds register unsigned long r3 asm("3") = (unsigned long) l2; 2561da177e4SLinus Torvalds register unsigned long r4 asm("4") = (unsigned long) s2; 2571da177e4SLinus Torvalds register unsigned long r5 asm("5") = (unsigned long) l2; 2581da177e4SLinus Torvalds int cc; 2591da177e4SLinus Torvalds 2601da177e4SLinus Torvalds asm volatile ("0: clcle %1,%3,0\n" 2611da177e4SLinus Torvalds " jo 0b\n" 2621da177e4SLinus Torvalds " ipm %0\n" 2631da177e4SLinus Torvalds " srl %0,28" 2641da177e4SLinus Torvalds : "=&d" (cc), "+a" (r2), "+a" (r3), 2651da177e4SLinus Torvalds "+a" (r4), "+a" (r5) : : "cc" ); 2661da177e4SLinus Torvalds if (!cc) 2671da177e4SLinus Torvalds return (char *) s1; 2681da177e4SLinus Torvalds s1++; 2691da177e4SLinus Torvalds } 270*d2c993d8SHeiko Carstens return NULL; 2711da177e4SLinus Torvalds } 2721da177e4SLinus Torvalds EXPORT_SYMBOL(strstr); 2731da177e4SLinus Torvalds 2741da177e4SLinus Torvalds /** 2751da177e4SLinus Torvalds * memchr - Find a character in an area of memory. 2761da177e4SLinus Torvalds * @s: The memory area 2771da177e4SLinus Torvalds * @c: The byte to search for 2781da177e4SLinus Torvalds * @n: The size of the area. 2791da177e4SLinus Torvalds * 2801da177e4SLinus Torvalds * returns the address of the first occurrence of @c, or %NULL 2811da177e4SLinus Torvalds * if @c is not found 2821da177e4SLinus Torvalds */ 2831da177e4SLinus Torvalds void *memchr(const void *s, int c, size_t n) 2841da177e4SLinus Torvalds { 2851da177e4SLinus Torvalds register int r0 asm("0") = (char) c; 2861da177e4SLinus Torvalds const void *ret = s + n; 2871da177e4SLinus Torvalds 2881da177e4SLinus Torvalds asm volatile ("0: srst %0,%1\n" 2891da177e4SLinus Torvalds " jo 0b\n" 2901da177e4SLinus Torvalds " jl 1f\n" 2911da177e4SLinus Torvalds " la %0,0\n" 2921da177e4SLinus Torvalds "1:" 2931da177e4SLinus Torvalds : "+a" (ret), "+&a" (s) : "d" (r0) : "cc" ); 2941da177e4SLinus Torvalds return (void *) ret; 2951da177e4SLinus Torvalds } 2961da177e4SLinus Torvalds EXPORT_SYMBOL(memchr); 2971da177e4SLinus Torvalds 2981da177e4SLinus Torvalds /** 2991da177e4SLinus Torvalds * memcmp - Compare two areas of memory 3001da177e4SLinus Torvalds * @cs: One area of memory 3011da177e4SLinus Torvalds * @ct: Another area of memory 3021da177e4SLinus Torvalds * @count: The size of the area. 3031da177e4SLinus Torvalds */ 3041da177e4SLinus Torvalds int memcmp(const void *cs, const void *ct, size_t n) 3051da177e4SLinus Torvalds { 3061da177e4SLinus Torvalds register unsigned long r2 asm("2") = (unsigned long) cs; 3071da177e4SLinus Torvalds register unsigned long r3 asm("3") = (unsigned long) n; 3081da177e4SLinus Torvalds register unsigned long r4 asm("4") = (unsigned long) ct; 3091da177e4SLinus Torvalds register unsigned long r5 asm("5") = (unsigned long) n; 3101da177e4SLinus Torvalds int ret; 3111da177e4SLinus Torvalds 3121da177e4SLinus Torvalds asm volatile ("0: clcle %1,%3,0\n" 3131da177e4SLinus Torvalds " jo 0b\n" 3141da177e4SLinus Torvalds " ipm %0\n" 3151da177e4SLinus Torvalds " srl %0,28" 3161da177e4SLinus Torvalds : "=&d" (ret), "+a" (r2), "+a" (r3), "+a" (r4), "+a" (r5) 3171da177e4SLinus Torvalds : : "cc" ); 3181da177e4SLinus Torvalds if (ret) 3191da177e4SLinus Torvalds ret = *(char *) r2 - *(char *) r4; 3201da177e4SLinus Torvalds return ret; 3211da177e4SLinus Torvalds } 3221da177e4SLinus Torvalds EXPORT_SYMBOL(memcmp); 3231da177e4SLinus Torvalds 3241da177e4SLinus Torvalds /** 3251da177e4SLinus Torvalds * memscan - Find a character in an area of memory. 3261da177e4SLinus Torvalds * @s: The memory area 3271da177e4SLinus Torvalds * @c: The byte to search for 3281da177e4SLinus Torvalds * @n: The size of the area. 3291da177e4SLinus Torvalds * 3301da177e4SLinus Torvalds * returns the address of the first occurrence of @c, or 1 byte past 3311da177e4SLinus Torvalds * the area if @c is not found 3321da177e4SLinus Torvalds */ 3331da177e4SLinus Torvalds void *memscan(void *s, int c, size_t n) 3341da177e4SLinus Torvalds { 3351da177e4SLinus Torvalds register int r0 asm("0") = (char) c; 3361da177e4SLinus Torvalds const void *ret = s + n; 3371da177e4SLinus Torvalds 3381da177e4SLinus Torvalds asm volatile ("0: srst %0,%1\n" 3391da177e4SLinus Torvalds " jo 0b\n" 3401da177e4SLinus Torvalds : "+a" (ret), "+&a" (s) : "d" (r0) : "cc" ); 3411da177e4SLinus Torvalds return (void *) ret; 3421da177e4SLinus Torvalds } 3431da177e4SLinus Torvalds EXPORT_SYMBOL(memscan); 3441da177e4SLinus Torvalds 3451da177e4SLinus Torvalds /** 3461da177e4SLinus Torvalds * memcpy - Copy one area of memory to another 3471da177e4SLinus Torvalds * @dest: Where to copy to 3481da177e4SLinus Torvalds * @src: Where to copy from 3491da177e4SLinus Torvalds * @n: The size of the area. 3501da177e4SLinus Torvalds * 3511da177e4SLinus Torvalds * returns a pointer to @dest 3521da177e4SLinus Torvalds */ 3531da177e4SLinus Torvalds void *memcpy(void *dest, const void *src, size_t n) 3541da177e4SLinus Torvalds { 3551da177e4SLinus Torvalds return __builtin_memcpy(dest, src, n); 3561da177e4SLinus Torvalds } 3571da177e4SLinus Torvalds EXPORT_SYMBOL(memcpy); 3581da177e4SLinus Torvalds 3591da177e4SLinus Torvalds /** 3601da177e4SLinus Torvalds * memset - Fill a region of memory with the given value 3611da177e4SLinus Torvalds * @s: Pointer to the start of the area. 3621da177e4SLinus Torvalds * @c: The byte to fill the area with 3631da177e4SLinus Torvalds * @n: The size of the area. 3641da177e4SLinus Torvalds * 3651da177e4SLinus Torvalds * returns a pointer to @s 3661da177e4SLinus Torvalds */ 3671da177e4SLinus Torvalds void *memset(void *s, int c, size_t n) 3681da177e4SLinus Torvalds { 3691da177e4SLinus Torvalds char *xs; 3701da177e4SLinus Torvalds 3711da177e4SLinus Torvalds if (c == 0) 3721da177e4SLinus Torvalds return __builtin_memset(s, 0, n); 3731da177e4SLinus Torvalds 3741da177e4SLinus Torvalds xs = (char *) s; 3751da177e4SLinus Torvalds if (n > 0) 3761da177e4SLinus Torvalds do { 3771da177e4SLinus Torvalds *xs++ = c; 3781da177e4SLinus Torvalds } while (--n > 0); 3791da177e4SLinus Torvalds return s; 3801da177e4SLinus Torvalds } 3811da177e4SLinus Torvalds EXPORT_SYMBOL(memset); 382