1 /* 2 * arch/s390/lib/string.c 3 * Optimized string functions 4 * 5 * S390 version 6 * Copyright (C) 2004 IBM Deutschland Entwicklung GmbH, IBM Corporation 7 * Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com) 8 */ 9 10 #define IN_ARCH_STRING_C 1 11 12 #include <linux/types.h> 13 #include <linux/module.h> 14 15 /* 16 * Helper functions to find the end of a string 17 */ 18 static inline char *__strend(const char *s) 19 { 20 register unsigned long r0 asm("0") = 0; 21 22 asm volatile ("0: srst %0,%1\n" 23 " jo 0b" 24 : "+d" (r0), "+a" (s) : : "cc" ); 25 return (char *) r0; 26 } 27 28 static inline char *__strnend(const char *s, size_t n) 29 { 30 register unsigned long r0 asm("0") = 0; 31 const char *p = s + n; 32 33 asm volatile ("0: srst %0,%1\n" 34 " jo 0b" 35 : "+d" (p), "+a" (s) : "d" (r0) : "cc" ); 36 return (char *) p; 37 } 38 39 /** 40 * strlen - Find the length of a string 41 * @s: The string to be sized 42 * 43 * returns the length of @s 44 */ 45 size_t strlen(const char *s) 46 { 47 return __strend(s) - s; 48 } 49 EXPORT_SYMBOL(strlen); 50 51 /** 52 * strnlen - Find the length of a length-limited string 53 * @s: The string to be sized 54 * @n: The maximum number of bytes to search 55 * 56 * returns the minimum of the length of @s and @n 57 */ 58 size_t strnlen(const char * s, size_t n) 59 { 60 return __strnend(s, n) - s; 61 } 62 EXPORT_SYMBOL(strnlen); 63 64 /** 65 * strcpy - Copy a %NUL terminated string 66 * @dest: Where to copy the string to 67 * @src: Where to copy the string from 68 * 69 * returns a pointer to @dest 70 */ 71 char *strcpy(char *dest, const char *src) 72 { 73 register int r0 asm("0") = 0; 74 char *ret = dest; 75 76 asm volatile ("0: mvst %0,%1\n" 77 " jo 0b" 78 : "+&a" (dest), "+&a" (src) : "d" (r0) 79 : "cc", "memory" ); 80 return ret; 81 } 82 EXPORT_SYMBOL(strcpy); 83 84 /** 85 * strlcpy - Copy a %NUL terminated string into a sized buffer 86 * @dest: Where to copy the string to 87 * @src: Where to copy the string from 88 * @size: size of destination buffer 89 * 90 * Compatible with *BSD: the result is always a valid 91 * NUL-terminated string that fits in the buffer (unless, 92 * of course, the buffer size is zero). It does not pad 93 * out the result like strncpy() does. 94 */ 95 size_t strlcpy(char *dest, const char *src, size_t size) 96 { 97 size_t ret = __strend(src) - src; 98 99 if (size) { 100 size_t len = (ret >= size) ? size-1 : ret; 101 dest[len] = '\0'; 102 __builtin_memcpy(dest, src, len); 103 } 104 return ret; 105 } 106 EXPORT_SYMBOL(strlcpy); 107 108 /** 109 * strncpy - Copy a length-limited, %NUL-terminated string 110 * @dest: Where to copy the string to 111 * @src: Where to copy the string from 112 * @n: The maximum number of bytes to copy 113 * 114 * The result is not %NUL-terminated if the source exceeds 115 * @n bytes. 116 */ 117 char *strncpy(char *dest, const char *src, size_t n) 118 { 119 size_t len = __strnend(src, n) - src; 120 __builtin_memset(dest + len, 0, n - len); 121 __builtin_memcpy(dest, src, len); 122 return dest; 123 } 124 EXPORT_SYMBOL(strncpy); 125 126 /** 127 * strcat - Append one %NUL-terminated string to another 128 * @dest: The string to be appended to 129 * @src: The string to append to it 130 * 131 * returns a pointer to @dest 132 */ 133 char *strcat(char *dest, const char *src) 134 { 135 register int r0 asm("0") = 0; 136 unsigned long dummy; 137 char *ret = dest; 138 139 asm volatile ("0: srst %0,%1\n" 140 " jo 0b\n" 141 "1: mvst %0,%2\n" 142 " jo 1b" 143 : "=&a" (dummy), "+a" (dest), "+a" (src) 144 : "d" (r0), "0" (0UL) : "cc", "memory" ); 145 return ret; 146 } 147 EXPORT_SYMBOL(strcat); 148 149 /** 150 * strlcat - Append a length-limited, %NUL-terminated string to another 151 * @dest: The string to be appended to 152 * @src: The string to append to it 153 * @n: The size of the destination buffer. 154 */ 155 size_t strlcat(char *dest, const char *src, size_t n) 156 { 157 size_t dsize = __strend(dest) - dest; 158 size_t len = __strend(src) - src; 159 size_t res = dsize + len; 160 161 if (dsize < n) { 162 dest += dsize; 163 n -= dsize; 164 if (len >= n) 165 len = n - 1; 166 dest[len] = '\0'; 167 __builtin_memcpy(dest, src, len); 168 } 169 return res; 170 } 171 EXPORT_SYMBOL(strlcat); 172 173 /** 174 * strncat - Append a length-limited, %NUL-terminated string to another 175 * @dest: The string to be appended to 176 * @src: The string to append to it 177 * @n: The maximum numbers of bytes to copy 178 * 179 * returns a pointer to @dest 180 * 181 * Note that in contrast to strncpy, strncat ensures the result is 182 * terminated. 183 */ 184 char *strncat(char *dest, const char *src, size_t n) 185 { 186 size_t len = __strnend(src, n) - src; 187 char *p = __strend(dest); 188 189 p[len] = '\0'; 190 __builtin_memcpy(p, src, len); 191 return dest; 192 } 193 EXPORT_SYMBOL(strncat); 194 195 /** 196 * strcmp - Compare two strings 197 * @cs: One string 198 * @ct: Another string 199 * 200 * returns 0 if @cs and @ct are equal, 201 * < 0 if @cs is less than @ct 202 * > 0 if @cs is greater than @ct 203 */ 204 int strcmp(const char *cs, const char *ct) 205 { 206 register int r0 asm("0") = 0; 207 int ret = 0; 208 209 asm volatile ("0: clst %2,%3\n" 210 " jo 0b\n" 211 " je 1f\n" 212 " ic %0,0(%2)\n" 213 " ic %1,0(%3)\n" 214 " sr %0,%1\n" 215 "1:" 216 : "+d" (ret), "+d" (r0), "+a" (cs), "+a" (ct) 217 : : "cc" ); 218 return ret; 219 } 220 EXPORT_SYMBOL(strcmp); 221 222 /** 223 * strrchr - Find the last occurrence of a character in a string 224 * @s: The string to be searched 225 * @c: The character to search for 226 */ 227 char * strrchr(const char * s, int c) 228 { 229 size_t len = __strend(s) - s; 230 231 if (len) 232 do { 233 if (s[len] == (char) c) 234 return (char *) s + len; 235 } while (--len > 0); 236 return 0; 237 } 238 EXPORT_SYMBOL(strrchr); 239 240 /** 241 * strstr - Find the first substring in a %NUL terminated string 242 * @s1: The string to be searched 243 * @s2: The string to search for 244 */ 245 char * strstr(const char * s1,const char * s2) 246 { 247 int l1, l2; 248 249 l2 = __strend(s2) - s2; 250 if (!l2) 251 return (char *) s1; 252 l1 = __strend(s1) - s1; 253 while (l1-- >= l2) { 254 register unsigned long r2 asm("2") = (unsigned long) s1; 255 register unsigned long r3 asm("3") = (unsigned long) l2; 256 register unsigned long r4 asm("4") = (unsigned long) s2; 257 register unsigned long r5 asm("5") = (unsigned long) l2; 258 int cc; 259 260 asm volatile ("0: clcle %1,%3,0\n" 261 " jo 0b\n" 262 " ipm %0\n" 263 " srl %0,28" 264 : "=&d" (cc), "+a" (r2), "+a" (r3), 265 "+a" (r4), "+a" (r5) : : "cc" ); 266 if (!cc) 267 return (char *) s1; 268 s1++; 269 } 270 return 0; 271 } 272 EXPORT_SYMBOL(strstr); 273 274 /** 275 * memchr - Find a character in an area of memory. 276 * @s: The memory area 277 * @c: The byte to search for 278 * @n: The size of the area. 279 * 280 * returns the address of the first occurrence of @c, or %NULL 281 * if @c is not found 282 */ 283 void *memchr(const void *s, int c, size_t n) 284 { 285 register int r0 asm("0") = (char) c; 286 const void *ret = s + n; 287 288 asm volatile ("0: srst %0,%1\n" 289 " jo 0b\n" 290 " jl 1f\n" 291 " la %0,0\n" 292 "1:" 293 : "+a" (ret), "+&a" (s) : "d" (r0) : "cc" ); 294 return (void *) ret; 295 } 296 EXPORT_SYMBOL(memchr); 297 298 /** 299 * memcmp - Compare two areas of memory 300 * @cs: One area of memory 301 * @ct: Another area of memory 302 * @count: The size of the area. 303 */ 304 int memcmp(const void *cs, const void *ct, size_t n) 305 { 306 register unsigned long r2 asm("2") = (unsigned long) cs; 307 register unsigned long r3 asm("3") = (unsigned long) n; 308 register unsigned long r4 asm("4") = (unsigned long) ct; 309 register unsigned long r5 asm("5") = (unsigned long) n; 310 int ret; 311 312 asm volatile ("0: clcle %1,%3,0\n" 313 " jo 0b\n" 314 " ipm %0\n" 315 " srl %0,28" 316 : "=&d" (ret), "+a" (r2), "+a" (r3), "+a" (r4), "+a" (r5) 317 : : "cc" ); 318 if (ret) 319 ret = *(char *) r2 - *(char *) r4; 320 return ret; 321 } 322 EXPORT_SYMBOL(memcmp); 323 324 /** 325 * memscan - Find a character in an area of memory. 326 * @s: The memory area 327 * @c: The byte to search for 328 * @n: The size of the area. 329 * 330 * returns the address of the first occurrence of @c, or 1 byte past 331 * the area if @c is not found 332 */ 333 void *memscan(void *s, int c, size_t n) 334 { 335 register int r0 asm("0") = (char) c; 336 const void *ret = s + n; 337 338 asm volatile ("0: srst %0,%1\n" 339 " jo 0b\n" 340 : "+a" (ret), "+&a" (s) : "d" (r0) : "cc" ); 341 return (void *) ret; 342 } 343 EXPORT_SYMBOL(memscan); 344 345 /** 346 * memcpy - Copy one area of memory to another 347 * @dest: Where to copy to 348 * @src: Where to copy from 349 * @n: The size of the area. 350 * 351 * returns a pointer to @dest 352 */ 353 void *memcpy(void *dest, const void *src, size_t n) 354 { 355 return __builtin_memcpy(dest, src, n); 356 } 357 EXPORT_SYMBOL(memcpy); 358 359 /** 360 * memset - Fill a region of memory with the given value 361 * @s: Pointer to the start of the area. 362 * @c: The byte to fill the area with 363 * @n: The size of the area. 364 * 365 * returns a pointer to @s 366 */ 367 void *memset(void *s, int c, size_t n) 368 { 369 char *xs; 370 371 if (c == 0) 372 return __builtin_memset(s, 0, n); 373 374 xs = (char *) s; 375 if (n > 0) 376 do { 377 *xs++ = c; 378 } while (--n > 0); 379 return s; 380 } 381 EXPORT_SYMBOL(memset); 382