1 /* SPDX-License-Identifier: GPL-2.0 */ 2 #ifndef _ASM_X86_STRING_32_H 3 #define _ASM_X86_STRING_32_H 4 5 #ifdef __KERNEL__ 6 7 /* Let gcc decide whether to inline or use the out of line functions */ 8 9 #define __HAVE_ARCH_STRCPY 10 extern char *strcpy(char *dest, const char *src); 11 12 #define __HAVE_ARCH_STRCAT 13 extern char *strcat(char *dest, const char *src); 14 15 #define __HAVE_ARCH_STRNCAT 16 extern char *strncat(char *dest, const char *src, size_t count); 17 18 #define __HAVE_ARCH_STRCMP 19 extern int strcmp(const char *cs, const char *ct); 20 21 #define __HAVE_ARCH_STRNCMP 22 extern int strncmp(const char *cs, const char *ct, size_t count); 23 24 #define __HAVE_ARCH_STRCHR 25 extern char *strchr(const char *s, int c); 26 27 #define __HAVE_ARCH_STRLEN 28 extern size_t strlen(const char *s); 29 30 static __always_inline void *__memcpy(void *to, const void *from, size_t n) 31 { 32 int d0, d1, d2; 33 asm volatile("rep movsl\n\t" 34 "movl %4,%%ecx\n\t" 35 "andl $3,%%ecx\n\t" 36 "jz 1f\n\t" 37 "rep movsb\n\t" 38 "1:" 39 : "=&c" (d0), "=&D" (d1), "=&S" (d2) 40 : "0" (n / 4), "g" (n), "1" ((long)to), "2" ((long)from) 41 : "memory"); 42 return to; 43 } 44 45 /* 46 * This looks ugly, but the compiler can optimize it totally, 47 * as the count is constant. 48 */ 49 static __always_inline void *__constant_memcpy(void *to, const void *from, 50 size_t n) 51 { 52 long esi, edi; 53 if (!n) 54 return to; 55 56 switch (n) { 57 case 1: 58 *(char *)to = *(char *)from; 59 return to; 60 case 2: 61 *(short *)to = *(short *)from; 62 return to; 63 case 4: 64 *(int *)to = *(int *)from; 65 return to; 66 case 3: 67 *(short *)to = *(short *)from; 68 *((char *)to + 2) = *((char *)from + 2); 69 return to; 70 case 5: 71 *(int *)to = *(int *)from; 72 *((char *)to + 4) = *((char *)from + 4); 73 return to; 74 case 6: 75 *(int *)to = *(int *)from; 76 *((short *)to + 2) = *((short *)from + 2); 77 return to; 78 case 8: 79 *(int *)to = *(int *)from; 80 *((int *)to + 1) = *((int *)from + 1); 81 return to; 82 } 83 84 esi = (long)from; 85 edi = (long)to; 86 if (n >= 5 * 4) { 87 /* large block: use rep prefix */ 88 int ecx; 89 asm volatile("rep movsl" 90 : "=&c" (ecx), "=&D" (edi), "=&S" (esi) 91 : "0" (n / 4), "1" (edi), "2" (esi) 92 : "memory" 93 ); 94 } else { 95 /* small block: don't clobber ecx + smaller code */ 96 if (n >= 4 * 4) 97 asm volatile("movsl" 98 : "=&D"(edi), "=&S"(esi) 99 : "0"(edi), "1"(esi) 100 : "memory"); 101 if (n >= 3 * 4) 102 asm volatile("movsl" 103 : "=&D"(edi), "=&S"(esi) 104 : "0"(edi), "1"(esi) 105 : "memory"); 106 if (n >= 2 * 4) 107 asm volatile("movsl" 108 : "=&D"(edi), "=&S"(esi) 109 : "0"(edi), "1"(esi) 110 : "memory"); 111 if (n >= 1 * 4) 112 asm volatile("movsl" 113 : "=&D"(edi), "=&S"(esi) 114 : "0"(edi), "1"(esi) 115 : "memory"); 116 } 117 switch (n % 4) { 118 /* tail */ 119 case 0: 120 return to; 121 case 1: 122 asm volatile("movsb" 123 : "=&D"(edi), "=&S"(esi) 124 : "0"(edi), "1"(esi) 125 : "memory"); 126 return to; 127 case 2: 128 asm volatile("movsw" 129 : "=&D"(edi), "=&S"(esi) 130 : "0"(edi), "1"(esi) 131 : "memory"); 132 return to; 133 default: 134 asm volatile("movsw\n\tmovsb" 135 : "=&D"(edi), "=&S"(esi) 136 : "0"(edi), "1"(esi) 137 : "memory"); 138 return to; 139 } 140 } 141 142 #define __HAVE_ARCH_MEMCPY 143 extern void *memcpy(void *, const void *, size_t); 144 145 #ifndef CONFIG_FORTIFY_SOURCE 146 147 #define memcpy(t, f, n) __builtin_memcpy(t, f, n) 148 149 #endif /* !CONFIG_FORTIFY_SOURCE */ 150 151 #define __HAVE_ARCH_MEMMOVE 152 void *memmove(void *dest, const void *src, size_t n); 153 154 extern int memcmp(const void *, const void *, size_t); 155 #ifndef CONFIG_FORTIFY_SOURCE 156 #define memcmp __builtin_memcmp 157 #endif 158 159 #define __HAVE_ARCH_MEMCHR 160 extern void *memchr(const void *cs, int c, size_t count); 161 162 static inline void *__memset_generic(void *s, char c, size_t count) 163 { 164 int d0, d1; 165 asm volatile("rep stosb" 166 : "=&c" (d0), "=&D" (d1) 167 : "a" (c), "1" (s), "0" (count) 168 : "memory"); 169 return s; 170 } 171 172 /* we might want to write optimized versions of these later */ 173 #define __constant_count_memset(s, c, count) __memset_generic((s), (c), (count)) 174 175 /* Added by Gertjan van Wingerde to make minix and sysv module work */ 176 #define __HAVE_ARCH_STRNLEN 177 extern size_t strnlen(const char *s, size_t count); 178 /* end of additional stuff */ 179 180 #define __HAVE_ARCH_STRSTR 181 extern char *strstr(const char *cs, const char *ct); 182 183 #define __memset(s, c, count) \ 184 (__builtin_constant_p(count) \ 185 ? __constant_count_memset((s), (c), (count)) \ 186 : __memset_generic((s), (c), (count))) 187 188 #define __HAVE_ARCH_MEMSET 189 extern void *memset(void *, int, size_t); 190 #ifndef CONFIG_FORTIFY_SOURCE 191 #define memset(s, c, count) __builtin_memset(s, c, count) 192 #endif /* !CONFIG_FORTIFY_SOURCE */ 193 194 #define __HAVE_ARCH_MEMSET16 195 static inline void *memset16(uint16_t *s, uint16_t v, size_t n) 196 { 197 int d0, d1; 198 asm volatile("rep stosw" 199 : "=&c" (d0), "=&D" (d1) 200 : "a" (v), "1" (s), "0" (n) 201 : "memory"); 202 return s; 203 } 204 205 #define __HAVE_ARCH_MEMSET32 206 static inline void *memset32(uint32_t *s, uint32_t v, size_t n) 207 { 208 int d0, d1; 209 asm volatile("rep stosl" 210 : "=&c" (d0), "=&D" (d1) 211 : "a" (v), "1" (s), "0" (n) 212 : "memory"); 213 return s; 214 } 215 216 /* 217 * find the first occurrence of byte 'c', or 1 past the area if none 218 */ 219 #define __HAVE_ARCH_MEMSCAN 220 extern void *memscan(void *addr, int c, size_t size); 221 222 #endif /* __KERNEL__ */ 223 224 #endif /* _ASM_X86_STRING_32_H */ 225