0001
0002
0003
0004
0005
0006
0007
0008
0009
0010 #define IN_ARCH_STRING_C 1
0011 #ifndef __NO_FORTIFY
0012 # define __NO_FORTIFY
0013 #endif
0014
0015 #include <linux/types.h>
0016 #include <linux/string.h>
0017 #include <linux/export.h>
0018
0019
0020
0021
0022 static inline char *__strend(const char *s)
0023 {
0024 unsigned long e = 0;
0025
0026 asm volatile(
0027 " lghi 0,0\n"
0028 "0: srst %[e],%[s]\n"
0029 " jo 0b\n"
0030 : [e] "+&a" (e), [s] "+&a" (s)
0031 :
0032 : "cc", "memory", "0");
0033 return (char *)e;
0034 }
0035
0036 static inline char *__strnend(const char *s, size_t n)
0037 {
0038 const char *p = s + n;
0039
0040 asm volatile(
0041 " lghi 0,0\n"
0042 "0: srst %[p],%[s]\n"
0043 " jo 0b\n"
0044 : [p] "+&d" (p), [s] "+&a" (s)
0045 :
0046 : "cc", "memory", "0");
0047 return (char *)p;
0048 }
0049
0050
0051
0052
0053
0054
0055
0056 #ifdef __HAVE_ARCH_STRLEN
0057 size_t strlen(const char *s)
0058 {
0059 return __strend(s) - s;
0060 }
0061 EXPORT_SYMBOL(strlen);
0062 #endif
0063
0064
0065
0066
0067
0068
0069
0070
0071 #ifdef __HAVE_ARCH_STRNLEN
0072 size_t strnlen(const char *s, size_t n)
0073 {
0074 return __strnend(s, n) - s;
0075 }
0076 EXPORT_SYMBOL(strnlen);
0077 #endif
0078
0079
0080
0081
0082
0083
0084
0085
0086 #ifdef __HAVE_ARCH_STRCPY
0087 char *strcpy(char *dest, const char *src)
0088 {
0089 char *ret = dest;
0090
0091 asm volatile(
0092 " lghi 0,0\n"
0093 "0: mvst %[dest],%[src]\n"
0094 " jo 0b\n"
0095 : [dest] "+&a" (dest), [src] "+&a" (src)
0096 :
0097 : "cc", "memory", "0");
0098 return ret;
0099 }
0100 EXPORT_SYMBOL(strcpy);
0101 #endif
0102
0103
0104
0105
0106
0107
0108
0109
0110
0111
0112 #ifdef __HAVE_ARCH_STRNCPY
0113 char *strncpy(char *dest, const char *src, size_t n)
0114 {
0115 size_t len = __strnend(src, n) - src;
0116 memset(dest + len, 0, n - len);
0117 memcpy(dest, src, len);
0118 return dest;
0119 }
0120 EXPORT_SYMBOL(strncpy);
0121 #endif
0122
0123
0124
0125
0126
0127
0128
0129
0130 #ifdef __HAVE_ARCH_STRCAT
0131 char *strcat(char *dest, const char *src)
0132 {
0133 unsigned long dummy = 0;
0134 char *ret = dest;
0135
0136 asm volatile(
0137 " lghi 0,0\n"
0138 "0: srst %[dummy],%[dest]\n"
0139 " jo 0b\n"
0140 "1: mvst %[dummy],%[src]\n"
0141 " jo 1b\n"
0142 : [dummy] "+&a" (dummy), [dest] "+&a" (dest), [src] "+&a" (src)
0143 :
0144 : "cc", "memory", "0");
0145 return ret;
0146 }
0147 EXPORT_SYMBOL(strcat);
0148 #endif
0149
0150
0151
0152
0153
0154
0155
0156 #ifdef __HAVE_ARCH_STRLCAT
0157 size_t strlcat(char *dest, const char *src, size_t n)
0158 {
0159 size_t dsize = __strend(dest) - dest;
0160 size_t len = __strend(src) - src;
0161 size_t res = dsize + len;
0162
0163 if (dsize < n) {
0164 dest += dsize;
0165 n -= dsize;
0166 if (len >= n)
0167 len = n - 1;
0168 dest[len] = '\0';
0169 memcpy(dest, src, len);
0170 }
0171 return res;
0172 }
0173 EXPORT_SYMBOL(strlcat);
0174 #endif
0175
0176
0177
0178
0179
0180
0181
0182
0183
0184
0185
0186
0187 #ifdef __HAVE_ARCH_STRNCAT
0188 char *strncat(char *dest, const char *src, size_t n)
0189 {
0190 size_t len = __strnend(src, n) - src;
0191 char *p = __strend(dest);
0192
0193 p[len] = '\0';
0194 memcpy(p, src, len);
0195 return dest;
0196 }
0197 EXPORT_SYMBOL(strncat);
0198 #endif
0199
0200
0201
0202
0203
0204
0205
0206
0207
0208
0209 #ifdef __HAVE_ARCH_STRCMP
0210 int strcmp(const char *s1, const char *s2)
0211 {
0212 int ret = 0;
0213
0214 asm volatile(
0215 " lghi 0,0\n"
0216 "0: clst %[s1],%[s2]\n"
0217 " jo 0b\n"
0218 " je 1f\n"
0219 " ic %[ret],0(%[s1])\n"
0220 " ic 0,0(%[s2])\n"
0221 " sr %[ret],0\n"
0222 "1:"
0223 : [ret] "+&d" (ret), [s1] "+&a" (s1), [s2] "+&a" (s2)
0224 :
0225 : "cc", "memory", "0");
0226 return ret;
0227 }
0228 EXPORT_SYMBOL(strcmp);
0229 #endif
0230
0231 static inline int clcle(const char *s1, unsigned long l1,
0232 const char *s2, unsigned long l2)
0233 {
0234 union register_pair r1 = { .even = (unsigned long)s1, .odd = l1, };
0235 union register_pair r3 = { .even = (unsigned long)s2, .odd = l2, };
0236 int cc;
0237
0238 asm volatile(
0239 "0: clcle %[r1],%[r3],0\n"
0240 " jo 0b\n"
0241 " ipm %[cc]\n"
0242 " srl %[cc],28\n"
0243 : [cc] "=&d" (cc), [r1] "+&d" (r1.pair), [r3] "+&d" (r3.pair)
0244 :
0245 : "cc", "memory");
0246 return cc;
0247 }
0248
0249
0250
0251
0252
0253
0254 #ifdef __HAVE_ARCH_STRSTR
0255 char *strstr(const char *s1, const char *s2)
0256 {
0257 int l1, l2;
0258
0259 l2 = __strend(s2) - s2;
0260 if (!l2)
0261 return (char *) s1;
0262 l1 = __strend(s1) - s1;
0263 while (l1-- >= l2) {
0264 int cc;
0265
0266 cc = clcle(s1, l2, s2, l2);
0267 if (!cc)
0268 return (char *) s1;
0269 s1++;
0270 }
0271 return NULL;
0272 }
0273 EXPORT_SYMBOL(strstr);
0274 #endif
0275
0276
0277
0278
0279
0280
0281
0282
0283
0284
0285 #ifdef __HAVE_ARCH_MEMCHR
0286 void *memchr(const void *s, int c, size_t n)
0287 {
0288 const void *ret = s + n;
0289
0290 asm volatile(
0291 " lgr 0,%[c]\n"
0292 "0: srst %[ret],%[s]\n"
0293 " jo 0b\n"
0294 " jl 1f\n"
0295 " la %[ret],0\n"
0296 "1:"
0297 : [ret] "+&a" (ret), [s] "+&a" (s)
0298 : [c] "d" (c)
0299 : "cc", "memory", "0");
0300 return (void *) ret;
0301 }
0302 EXPORT_SYMBOL(memchr);
0303 #endif
0304
0305
0306
0307
0308
0309
0310
0311 #ifdef __HAVE_ARCH_MEMCMP
0312 int memcmp(const void *s1, const void *s2, size_t n)
0313 {
0314 int ret;
0315
0316 ret = clcle(s1, n, s2, n);
0317 if (ret)
0318 ret = ret == 1 ? -1 : 1;
0319 return ret;
0320 }
0321 EXPORT_SYMBOL(memcmp);
0322 #endif
0323
0324
0325
0326
0327
0328
0329
0330
0331
0332
0333 #ifdef __HAVE_ARCH_MEMSCAN
0334 void *memscan(void *s, int c, size_t n)
0335 {
0336 const void *ret = s + n;
0337
0338 asm volatile(
0339 " lgr 0,%[c]\n"
0340 "0: srst %[ret],%[s]\n"
0341 " jo 0b\n"
0342 : [ret] "+&a" (ret), [s] "+&a" (s)
0343 : [c] "d" (c)
0344 : "cc", "memory", "0");
0345 return (void *)ret;
0346 }
0347 EXPORT_SYMBOL(memscan);
0348 #endif