aboutsummaryrefslogtreecommitdiffstats
path: root/arch/s390/lib
diff options
context:
space:
mode:
authorHeiko Carstens <heiko.carstens@de.ibm.com>2012-08-14 07:20:20 -0400
committerMartin Schwidefsky <schwidefsky@de.ibm.com>2012-09-26 09:44:50 -0400
commit535c611ddd3eb076f96579131e30bc5dd02a3b1c (patch)
treef6e3fdb6c8870ab01e35e79a4f017c6f6a365fda /arch/s390/lib
parent68d9884dbc4215b6693c108eb35a02bd78f7956e (diff)
s390/string: provide asm lib functions for memcpy and memcmp
Our memcpy and memcmp variants were implemented by calling the corresponding gcc builtin variants. However gcc is free to replace a call to __builtin_memcmp with a call to memcmp which, when called, will result in an endless recursion within memcmp. So let's provide asm variants and also fix the variants that are used for uncompressing the kernel image. In addition remove all other occurences of builtin function calls. Signed-off-by: Heiko Carstens <heiko.carstens@de.ibm.com> Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
Diffstat (limited to 'arch/s390/lib')
-rw-r--r--arch/s390/lib/Makefile3
-rw-r--r--arch/s390/lib/mem32.S92
-rw-r--r--arch/s390/lib/mem64.S88
-rw-r--r--arch/s390/lib/string.c56
4 files changed, 187 insertions, 52 deletions
diff --git a/arch/s390/lib/Makefile b/arch/s390/lib/Makefile
index 761ab8b56afc..6ab0d0b5cec8 100644
--- a/arch/s390/lib/Makefile
+++ b/arch/s390/lib/Makefile
@@ -4,6 +4,7 @@
4 4
5lib-y += delay.o string.o uaccess_std.o uaccess_pt.o 5lib-y += delay.o string.o uaccess_std.o uaccess_pt.o
6obj-y += usercopy.o 6obj-y += usercopy.o
7obj-$(CONFIG_32BIT) += div64.o qrnnd.o ucmpdi2.o 7obj-$(CONFIG_32BIT) += div64.o qrnnd.o ucmpdi2.o mem32.o
8obj-$(CONFIG_64BIT) += mem64.o
8lib-$(CONFIG_64BIT) += uaccess_mvcos.o 9lib-$(CONFIG_64BIT) += uaccess_mvcos.o
9lib-$(CONFIG_SMP) += spinlock.o 10lib-$(CONFIG_SMP) += spinlock.o
diff --git a/arch/s390/lib/mem32.S b/arch/s390/lib/mem32.S
new file mode 100644
index 000000000000..14ca9244b615
--- /dev/null
+++ b/arch/s390/lib/mem32.S
@@ -0,0 +1,92 @@
1/*
2 * String handling functions.
3 *
4 * Copyright IBM Corp. 2012
5 */
6
7#include <linux/linkage.h>
8
9/*
10 * memset implementation
11 *
12 * This code corresponds to the C construct below. We do distinguish
13 * between clearing (c == 0) and setting a memory array (c != 0) simply
14 * because nearly all memset invocations in the kernel clear memory and
15 * the xc instruction is preferred in such cases.
16 *
17 * void *memset(void *s, int c, size_t n)
18 * {
19 * if (likely(c == 0))
20 * return __builtin_memset(s, 0, n);
21 * return __builtin_memset(s, c, n);
22 * }
23 */
24ENTRY(memset)
25 basr %r5,%r0
26.Lmemset_base:
27 ltr %r4,%r4
28 bzr %r14
29 ltr %r3,%r3
30 jnz .Lmemset_fill
31 ahi %r4,-1
32 lr %r3,%r4
33 srl %r3,8
34 ltr %r3,%r3
35 lr %r1,%r2
36 je .Lmemset_clear_rest
37.Lmemset_clear_loop:
38 xc 0(256,%r1),0(%r1)
39 la %r1,256(%r1)
40 brct %r3,.Lmemset_clear_loop
41.Lmemset_clear_rest:
42 ex %r4,.Lmemset_xc-.Lmemset_base(%r5)
43 br %r14
44.Lmemset_fill:
45 stc %r3,0(%r2)
46 chi %r4,1
47 lr %r1,%r2
48 ber %r14
49 ahi %r4,-2
50 lr %r3,%r4
51 srl %r3,8
52 ltr %r3,%r3
53 je .Lmemset_fill_rest
54.Lmemset_fill_loop:
55 mvc 1(256,%r1),0(%r1)
56 la %r1,256(%r1)
57 brct %r3,.Lmemset_fill_loop
58.Lmemset_fill_rest:
59 ex %r4,.Lmemset_mvc-.Lmemset_base(%r5)
60 br %r14
61.Lmemset_xc:
62 xc 0(1,%r1),0(%r1)
63.Lmemset_mvc:
64 mvc 1(1,%r1),0(%r1)
65
66/*
67 * memcpy implementation
68 *
69 * void *memcpy(void *dest, const void *src, size_t n)
70 */
71ENTRY(memcpy)
72 basr %r5,%r0
73.Lmemcpy_base:
74 ltr %r4,%r4
75 bzr %r14
76 ahi %r4,-1
77 lr %r0,%r4
78 srl %r0,8
79 ltr %r0,%r0
80 lr %r1,%r2
81 jnz .Lmemcpy_loop
82.Lmemcpy_rest:
83 ex %r4,.Lmemcpy_mvc-.Lmemcpy_base(%r5)
84 br %r14
85.Lmemcpy_loop:
86 mvc 0(256,%r1),0(%r3)
87 la %r1,256(%r1)
88 la %r3,256(%r3)
89 brct %r0,.Lmemcpy_loop
90 j .Lmemcpy_rest
91.Lmemcpy_mvc:
92 mvc 0(1,%r1),0(%r3)
diff --git a/arch/s390/lib/mem64.S b/arch/s390/lib/mem64.S
new file mode 100644
index 000000000000..c6d553e85ab1
--- /dev/null
+++ b/arch/s390/lib/mem64.S
@@ -0,0 +1,88 @@
1/*
2 * String handling functions.
3 *
4 * Copyright IBM Corp. 2012
5 */
6
7#include <linux/linkage.h>
8
9/*
10 * memset implementation
11 *
12 * This code corresponds to the C construct below. We do distinguish
13 * between clearing (c == 0) and setting a memory array (c != 0) simply
14 * because nearly all memset invocations in the kernel clear memory and
15 * the xc instruction is preferred in such cases.
16 *
17 * void *memset(void *s, int c, size_t n)
18 * {
19 * if (likely(c == 0))
20 * return __builtin_memset(s, 0, n);
21 * return __builtin_memset(s, c, n);
22 * }
23 */
24ENTRY(memset)
25 ltgr %r4,%r4
26 bzr %r14
27 ltgr %r3,%r3
28 jnz .Lmemset_fill
29 aghi %r4,-1
30 srlg %r3,%r4,8
31 ltgr %r3,%r3
32 lgr %r1,%r2
33 jz .Lmemset_clear_rest
34.Lmemset_clear_loop:
35 xc 0(256,%r1),0(%r1)
36 la %r1,256(%r1)
37 brctg %r3,.Lmemset_clear_loop
38.Lmemset_clear_rest:
39 larl %r3,.Lmemset_xc
40 ex %r4,0(%r3)
41 br %r14
42.Lmemset_fill:
43 stc %r3,0(%r2)
44 cghi %r4,1
45 lgr %r1,%r2
46 ber %r14
47 aghi %r4,-2
48 srlg %r3,%r4,8
49 ltgr %r3,%r3
50 jz .Lmemset_fill_rest
51.Lmemset_fill_loop:
52 mvc 1(256,%r1),0(%r1)
53 la %r1,256(%r1)
54 brctg %r3,.Lmemset_fill_loop
55.Lmemset_fill_rest:
56 larl %r3,.Lmemset_mvc
57 ex %r4,0(%r3)
58 br %r14
59.Lmemset_xc:
60 xc 0(1,%r1),0(%r1)
61.Lmemset_mvc:
62 mvc 1(1,%r1),0(%r1)
63
64/*
65 * memcpy implementation
66 *
67 * void *memcpy(void *dest, const void *src, size_t n)
68 */
69ENTRY(memcpy)
70 ltgr %r4,%r4
71 bzr %r14
72 aghi %r4,-1
73 srlg %r5,%r4,8
74 ltgr %r5,%r5
75 lgr %r1,%r2
76 jnz .Lmemcpy_loop
77.Lmemcpy_rest:
78 larl %r5,.Lmemcpy_mvc
79 ex %r4,0(%r5)
80 br %r14
81.Lmemcpy_loop:
82 mvc 0(256,%r1),0(%r3)
83 la %r1,256(%r1)
84 la %r3,256(%r3)
85 brctg %r5,.Lmemcpy_loop
86 j .Lmemcpy_rest
87.Lmemcpy_mvc:
88 mvc 0(1,%r1),0(%r3)
diff --git a/arch/s390/lib/string.c b/arch/s390/lib/string.c
index 846ec64ab2c9..b647d5ff0ad9 100644
--- a/arch/s390/lib/string.c
+++ b/arch/s390/lib/string.c
@@ -43,11 +43,7 @@ static inline char *__strnend(const char *s, size_t n)
43 */ 43 */
44size_t strlen(const char *s) 44size_t strlen(const char *s)
45{ 45{
46#if __GNUC__ < 4
47 return __strend(s) - s; 46 return __strend(s) - s;
48#else
49 return __builtin_strlen(s);
50#endif
51} 47}
52EXPORT_SYMBOL(strlen); 48EXPORT_SYMBOL(strlen);
53 49
@@ -73,7 +69,6 @@ EXPORT_SYMBOL(strnlen);
73 */ 69 */
74char *strcpy(char *dest, const char *src) 70char *strcpy(char *dest, const char *src)
75{ 71{
76#if __GNUC__ < 4
77 register int r0 asm("0") = 0; 72 register int r0 asm("0") = 0;
78 char *ret = dest; 73 char *ret = dest;
79 74
@@ -82,9 +77,6 @@ char *strcpy(char *dest, const char *src)
82 : "+&a" (dest), "+&a" (src) : "d" (r0) 77 : "+&a" (dest), "+&a" (src) : "d" (r0)
83 : "cc", "memory" ); 78 : "cc", "memory" );
84 return ret; 79 return ret;
85#else
86 return __builtin_strcpy(dest, src);
87#endif
88} 80}
89EXPORT_SYMBOL(strcpy); 81EXPORT_SYMBOL(strcpy);
90 82
@@ -106,7 +98,7 @@ size_t strlcpy(char *dest, const char *src, size_t size)
106 if (size) { 98 if (size) {
107 size_t len = (ret >= size) ? size-1 : ret; 99 size_t len = (ret >= size) ? size-1 : ret;
108 dest[len] = '\0'; 100 dest[len] = '\0';
109 __builtin_memcpy(dest, src, len); 101 memcpy(dest, src, len);
110 } 102 }
111 return ret; 103 return ret;
112} 104}
@@ -124,8 +116,8 @@ EXPORT_SYMBOL(strlcpy);
124char *strncpy(char *dest, const char *src, size_t n) 116char *strncpy(char *dest, const char *src, size_t n)
125{ 117{
126 size_t len = __strnend(src, n) - src; 118 size_t len = __strnend(src, n) - src;
127 __builtin_memset(dest + len, 0, n - len); 119 memset(dest + len, 0, n - len);
128 __builtin_memcpy(dest, src, len); 120 memcpy(dest, src, len);
129 return dest; 121 return dest;
130} 122}
131EXPORT_SYMBOL(strncpy); 123EXPORT_SYMBOL(strncpy);
@@ -171,7 +163,7 @@ size_t strlcat(char *dest, const char *src, size_t n)
171 if (len >= n) 163 if (len >= n)
172 len = n - 1; 164 len = n - 1;
173 dest[len] = '\0'; 165 dest[len] = '\0';
174 __builtin_memcpy(dest, src, len); 166 memcpy(dest, src, len);
175 } 167 }
176 return res; 168 return res;
177} 169}
@@ -194,7 +186,7 @@ char *strncat(char *dest, const char *src, size_t n)
194 char *p = __strend(dest); 186 char *p = __strend(dest);
195 187
196 p[len] = '\0'; 188 p[len] = '\0';
197 __builtin_memcpy(p, src, len); 189 memcpy(p, src, len);
198 return dest; 190 return dest;
199} 191}
200EXPORT_SYMBOL(strncat); 192EXPORT_SYMBOL(strncat);
@@ -348,41 +340,3 @@ void *memscan(void *s, int c, size_t n)
348 return (void *) ret; 340 return (void *) ret;
349} 341}
350EXPORT_SYMBOL(memscan); 342EXPORT_SYMBOL(memscan);
351
352/**
353 * memcpy - Copy one area of memory to another
354 * @dest: Where to copy to
355 * @src: Where to copy from
356 * @n: The size of the area.
357 *
358 * returns a pointer to @dest
359 */
360void *memcpy(void *dest, const void *src, size_t n)
361{
362 return __builtin_memcpy(dest, src, n);
363}
364EXPORT_SYMBOL(memcpy);
365
366/**
367 * memset - Fill a region of memory with the given value
368 * @s: Pointer to the start of the area.
369 * @c: The byte to fill the area with
370 * @n: The size of the area.
371 *
372 * returns a pointer to @s
373 */
374void *memset(void *s, int c, size_t n)
375{
376 char *xs;
377
378 if (c == 0)
379 return __builtin_memset(s, 0, n);
380
381 xs = (char *) s;
382 if (n > 0)
383 do {
384 *xs++ = c;
385 } while (--n > 0);
386 return s;
387}
388EXPORT_SYMBOL(memset);