projects/linux·blob master · refs

224 lines · 5.2 KiB

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
10extern char *strcpy(char *dest, const char *src);
11
12#define __HAVE_ARCH_STRCAT
13extern char *strcat(char *dest, const char *src);
14
15#define __HAVE_ARCH_STRNCAT
16extern char *strncat(char *dest, const char *src, size_t count);
17
18#define __HAVE_ARCH_STRCMP
19extern int strcmp(const char *cs, const char *ct);
20
21#define __HAVE_ARCH_STRNCMP
22extern int strncmp(const char *cs, const char *ct, size_t count);
23
24#define __HAVE_ARCH_STRCHR
25extern char *strchr(const char *s, int c);
26
27#define __HAVE_ARCH_STRLEN
28extern size_t strlen(const char *s);
29
30static __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 */
49static __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
143extern 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
152void *memmove(void *dest, const void *src, size_t n);
153
154extern 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
160extern void *memchr(const void *cs, int c, size_t count);
161
162static 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
177extern size_t strnlen(const char *s, size_t count);
178/* end of additional stuff */
179
180#define __HAVE_ARCH_STRSTR
181extern 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
189extern 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
195static 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
206static 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
220extern void *memscan(void *addr, int c, size_t size);
221
222#endif /* __KERNEL__ */
223
224#endif /* _ASM_X86_STRING_32_H */