xref: /linux/arch/x86/include/asm/string_32.h (revision bba2c3615bd6cfee7456d1130f2e6b01b3f4e9ba)
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