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