Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Heiko Carstens and committed by
Martin Schwidefsky
535c611d 68d9884d

+212 -80
+23 -20
arch/s390/boot/compressed/misc.c
··· 71 71 { 72 72 char *xs; 73 73 74 - if (c == 0) 75 - return __builtin_memset(s, 0, n); 76 - 77 - xs = (char *) s; 78 - if (n > 0) 79 - do { 80 - *xs++ = c; 81 - } while (--n > 0); 74 + xs = s; 75 + while (n--) 76 + *xs++ = c; 82 77 return s; 83 78 } 84 79 85 - void *memcpy(void *__dest, __const void *__src, size_t __n) 80 + void *memcpy(void *dest, const void *src, size_t n) 86 81 { 87 - return __builtin_memcpy(__dest, __src, __n); 82 + const char *s = src; 83 + char *d = dest; 84 + 85 + while (n--) 86 + *d++ = *s++; 87 + return dest; 88 88 } 89 89 90 - void *memmove(void *__dest, __const void *__src, size_t __n) 90 + void *memmove(void *dest, const void *src, size_t n) 91 91 { 92 - char *d; 93 - const char *s; 92 + const char *s = src; 93 + char *d = dest; 94 94 95 - if (__dest <= __src) 96 - return __builtin_memcpy(__dest, __src, __n); 97 - d = __dest + __n; 98 - s = __src + __n; 99 - while (__n--) 100 - *--d = *--s; 101 - return __dest; 95 + if (d <= s) { 96 + while (n--) 97 + *d++ = *s++; 98 + } else { 99 + d += n; 100 + s += n; 101 + while (n--) 102 + *--d = *--s; 103 + } 104 + return dest; 102 105 } 103 106 104 107 static void error(char *x)
-8
arch/s390/include/asm/string.h
··· 96 96 97 97 static inline char *strcpy(char *dst, const char *src) 98 98 { 99 - #if __GNUC__ < 4 100 99 register int r0 asm("0") = 0; 101 100 char *ret = dst; 102 101 ··· 105 106 : "+&a" (dst), "+&a" (src) : "d" (r0) 106 107 : "cc", "memory"); 107 108 return ret; 108 - #else 109 - return __builtin_strcpy(dst, src); 110 - #endif 111 109 } 112 110 113 111 static inline size_t strlen(const char *s) 114 112 { 115 - #if __GNUC__ < 4 116 113 register unsigned long r0 asm("0") = 0; 117 114 const char *tmp = s; 118 115 ··· 117 122 " jo 0b" 118 123 : "+d" (r0), "+a" (tmp) : : "cc"); 119 124 return r0 - (unsigned long) s; 120 - #else 121 - return __builtin_strlen(s); 122 - #endif 123 125 } 124 126 125 127 static inline size_t strnlen(const char * s, size_t n)
+2
arch/s390/kernel/s390_ksyms.c
··· 8 8 #if defined(CONFIG_KVM) || defined(CONFIG_KVM_MODULE) 9 9 EXPORT_SYMBOL(sie64a); 10 10 #endif 11 + EXPORT_SYMBOL(memcpy); 12 + EXPORT_SYMBOL(memset);
+2 -1
arch/s390/lib/Makefile
··· 4 4 5 5 lib-y += delay.o string.o uaccess_std.o uaccess_pt.o 6 6 obj-y += usercopy.o 7 - obj-$(CONFIG_32BIT) += div64.o qrnnd.o ucmpdi2.o 7 + obj-$(CONFIG_32BIT) += div64.o qrnnd.o ucmpdi2.o mem32.o 8 + obj-$(CONFIG_64BIT) += mem64.o 8 9 lib-$(CONFIG_64BIT) += uaccess_mvcos.o 9 10 lib-$(CONFIG_SMP) += spinlock.o
+92
arch/s390/lib/mem32.S
··· 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 + */ 24 + ENTRY(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 + */ 71 + ENTRY(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)
+88
arch/s390/lib/mem64.S
··· 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 + */ 24 + ENTRY(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 + */ 69 + ENTRY(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)
+5 -51
arch/s390/lib/string.c
··· 43 43 */ 44 44 size_t strlen(const char *s) 45 45 { 46 - #if __GNUC__ < 4 47 46 return __strend(s) - s; 48 - #else 49 - return __builtin_strlen(s); 50 - #endif 51 47 } 52 48 EXPORT_SYMBOL(strlen); 53 49 ··· 69 73 */ 70 74 char *strcpy(char *dest, const char *src) 71 75 { 72 - #if __GNUC__ < 4 73 76 register int r0 asm("0") = 0; 74 77 char *ret = dest; 75 78 ··· 77 82 : "+&a" (dest), "+&a" (src) : "d" (r0) 78 83 : "cc", "memory" ); 79 84 return ret; 80 - #else 81 - return __builtin_strcpy(dest, src); 82 - #endif 83 85 } 84 86 EXPORT_SYMBOL(strcpy); 85 87 ··· 98 106 if (size) { 99 107 size_t len = (ret >= size) ? size-1 : ret; 100 108 dest[len] = '\0'; 101 - __builtin_memcpy(dest, src, len); 109 + memcpy(dest, src, len); 102 110 } 103 111 return ret; 104 112 } ··· 116 124 char *strncpy(char *dest, const char *src, size_t n) 117 125 { 118 126 size_t len = __strnend(src, n) - src; 119 - __builtin_memset(dest + len, 0, n - len); 120 - __builtin_memcpy(dest, src, len); 127 + memset(dest + len, 0, n - len); 128 + memcpy(dest, src, len); 121 129 return dest; 122 130 } 123 131 EXPORT_SYMBOL(strncpy); ··· 163 171 if (len >= n) 164 172 len = n - 1; 165 173 dest[len] = '\0'; 166 - __builtin_memcpy(dest, src, len); 174 + memcpy(dest, src, len); 167 175 } 168 176 return res; 169 177 } ··· 186 194 char *p = __strend(dest); 187 195 188 196 p[len] = '\0'; 189 - __builtin_memcpy(p, src, len); 197 + memcpy(p, src, len); 190 198 return dest; 191 199 } 192 200 EXPORT_SYMBOL(strncat); ··· 340 348 return (void *) ret; 341 349 } 342 350 EXPORT_SYMBOL(memscan); 343 - 344 - /** 345 - * memcpy - Copy one area of memory to another 346 - * @dest: Where to copy to 347 - * @src: Where to copy from 348 - * @n: The size of the area. 349 - * 350 - * returns a pointer to @dest 351 - */ 352 - void *memcpy(void *dest, const void *src, size_t n) 353 - { 354 - return __builtin_memcpy(dest, src, n); 355 - } 356 - EXPORT_SYMBOL(memcpy); 357 - 358 - /** 359 - * memset - Fill a region of memory with the given value 360 - * @s: Pointer to the start of the area. 361 - * @c: The byte to fill the area with 362 - * @n: The size of the area. 363 - * 364 - * returns a pointer to @s 365 - */ 366 - void *memset(void *s, int c, size_t n) 367 - { 368 - char *xs; 369 - 370 - if (c == 0) 371 - return __builtin_memset(s, 0, n); 372 - 373 - xs = (char *) s; 374 - if (n > 0) 375 - do { 376 - *xs++ = c; 377 - } while (--n > 0); 378 - return s; 379 - } 380 - EXPORT_SYMBOL(memset);