162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 */
262306a36Sopenharmony_ci#ifndef _ASM_X86_STRING_32_H
362306a36Sopenharmony_ci#define _ASM_X86_STRING_32_H
462306a36Sopenharmony_ci
562306a36Sopenharmony_ci#ifdef __KERNEL__
662306a36Sopenharmony_ci
762306a36Sopenharmony_ci/* Let gcc decide whether to inline or use the out of line functions */
862306a36Sopenharmony_ci
962306a36Sopenharmony_ci#define __HAVE_ARCH_STRCPY
1062306a36Sopenharmony_ciextern char *strcpy(char *dest, const char *src);
1162306a36Sopenharmony_ci
1262306a36Sopenharmony_ci#define __HAVE_ARCH_STRNCPY
1362306a36Sopenharmony_ciextern char *strncpy(char *dest, const char *src, size_t count);
1462306a36Sopenharmony_ci
1562306a36Sopenharmony_ci#define __HAVE_ARCH_STRCAT
1662306a36Sopenharmony_ciextern char *strcat(char *dest, const char *src);
1762306a36Sopenharmony_ci
1862306a36Sopenharmony_ci#define __HAVE_ARCH_STRNCAT
1962306a36Sopenharmony_ciextern char *strncat(char *dest, const char *src, size_t count);
2062306a36Sopenharmony_ci
2162306a36Sopenharmony_ci#define __HAVE_ARCH_STRCMP
2262306a36Sopenharmony_ciextern int strcmp(const char *cs, const char *ct);
2362306a36Sopenharmony_ci
2462306a36Sopenharmony_ci#define __HAVE_ARCH_STRNCMP
2562306a36Sopenharmony_ciextern int strncmp(const char *cs, const char *ct, size_t count);
2662306a36Sopenharmony_ci
2762306a36Sopenharmony_ci#define __HAVE_ARCH_STRCHR
2862306a36Sopenharmony_ciextern char *strchr(const char *s, int c);
2962306a36Sopenharmony_ci
3062306a36Sopenharmony_ci#define __HAVE_ARCH_STRLEN
3162306a36Sopenharmony_ciextern size_t strlen(const char *s);
3262306a36Sopenharmony_ci
3362306a36Sopenharmony_cistatic __always_inline void *__memcpy(void *to, const void *from, size_t n)
3462306a36Sopenharmony_ci{
3562306a36Sopenharmony_ci	int d0, d1, d2;
3662306a36Sopenharmony_ci	asm volatile("rep ; movsl\n\t"
3762306a36Sopenharmony_ci		     "movl %4,%%ecx\n\t"
3862306a36Sopenharmony_ci		     "andl $3,%%ecx\n\t"
3962306a36Sopenharmony_ci		     "jz 1f\n\t"
4062306a36Sopenharmony_ci		     "rep ; movsb\n\t"
4162306a36Sopenharmony_ci		     "1:"
4262306a36Sopenharmony_ci		     : "=&c" (d0), "=&D" (d1), "=&S" (d2)
4362306a36Sopenharmony_ci		     : "0" (n / 4), "g" (n), "1" ((long)to), "2" ((long)from)
4462306a36Sopenharmony_ci		     : "memory");
4562306a36Sopenharmony_ci	return to;
4662306a36Sopenharmony_ci}
4762306a36Sopenharmony_ci
4862306a36Sopenharmony_ci/*
4962306a36Sopenharmony_ci * This looks ugly, but the compiler can optimize it totally,
5062306a36Sopenharmony_ci * as the count is constant.
5162306a36Sopenharmony_ci */
5262306a36Sopenharmony_cistatic __always_inline void *__constant_memcpy(void *to, const void *from,
5362306a36Sopenharmony_ci					       size_t n)
5462306a36Sopenharmony_ci{
5562306a36Sopenharmony_ci	long esi, edi;
5662306a36Sopenharmony_ci	if (!n)
5762306a36Sopenharmony_ci		return to;
5862306a36Sopenharmony_ci
5962306a36Sopenharmony_ci	switch (n) {
6062306a36Sopenharmony_ci	case 1:
6162306a36Sopenharmony_ci		*(char *)to = *(char *)from;
6262306a36Sopenharmony_ci		return to;
6362306a36Sopenharmony_ci	case 2:
6462306a36Sopenharmony_ci		*(short *)to = *(short *)from;
6562306a36Sopenharmony_ci		return to;
6662306a36Sopenharmony_ci	case 4:
6762306a36Sopenharmony_ci		*(int *)to = *(int *)from;
6862306a36Sopenharmony_ci		return to;
6962306a36Sopenharmony_ci	case 3:
7062306a36Sopenharmony_ci		*(short *)to = *(short *)from;
7162306a36Sopenharmony_ci		*((char *)to + 2) = *((char *)from + 2);
7262306a36Sopenharmony_ci		return to;
7362306a36Sopenharmony_ci	case 5:
7462306a36Sopenharmony_ci		*(int *)to = *(int *)from;
7562306a36Sopenharmony_ci		*((char *)to + 4) = *((char *)from + 4);
7662306a36Sopenharmony_ci		return to;
7762306a36Sopenharmony_ci	case 6:
7862306a36Sopenharmony_ci		*(int *)to = *(int *)from;
7962306a36Sopenharmony_ci		*((short *)to + 2) = *((short *)from + 2);
8062306a36Sopenharmony_ci		return to;
8162306a36Sopenharmony_ci	case 8:
8262306a36Sopenharmony_ci		*(int *)to = *(int *)from;
8362306a36Sopenharmony_ci		*((int *)to + 1) = *((int *)from + 1);
8462306a36Sopenharmony_ci		return to;
8562306a36Sopenharmony_ci	}
8662306a36Sopenharmony_ci
8762306a36Sopenharmony_ci	esi = (long)from;
8862306a36Sopenharmony_ci	edi = (long)to;
8962306a36Sopenharmony_ci	if (n >= 5 * 4) {
9062306a36Sopenharmony_ci		/* large block: use rep prefix */
9162306a36Sopenharmony_ci		int ecx;
9262306a36Sopenharmony_ci		asm volatile("rep ; movsl"
9362306a36Sopenharmony_ci			     : "=&c" (ecx), "=&D" (edi), "=&S" (esi)
9462306a36Sopenharmony_ci			     : "0" (n / 4), "1" (edi), "2" (esi)
9562306a36Sopenharmony_ci			     : "memory"
9662306a36Sopenharmony_ci		);
9762306a36Sopenharmony_ci	} else {
9862306a36Sopenharmony_ci		/* small block: don't clobber ecx + smaller code */
9962306a36Sopenharmony_ci		if (n >= 4 * 4)
10062306a36Sopenharmony_ci			asm volatile("movsl"
10162306a36Sopenharmony_ci				     : "=&D"(edi), "=&S"(esi)
10262306a36Sopenharmony_ci				     : "0"(edi), "1"(esi)
10362306a36Sopenharmony_ci				     : "memory");
10462306a36Sopenharmony_ci		if (n >= 3 * 4)
10562306a36Sopenharmony_ci			asm volatile("movsl"
10662306a36Sopenharmony_ci				     : "=&D"(edi), "=&S"(esi)
10762306a36Sopenharmony_ci				     : "0"(edi), "1"(esi)
10862306a36Sopenharmony_ci				     : "memory");
10962306a36Sopenharmony_ci		if (n >= 2 * 4)
11062306a36Sopenharmony_ci			asm volatile("movsl"
11162306a36Sopenharmony_ci				     : "=&D"(edi), "=&S"(esi)
11262306a36Sopenharmony_ci				     : "0"(edi), "1"(esi)
11362306a36Sopenharmony_ci				     : "memory");
11462306a36Sopenharmony_ci		if (n >= 1 * 4)
11562306a36Sopenharmony_ci			asm volatile("movsl"
11662306a36Sopenharmony_ci				     : "=&D"(edi), "=&S"(esi)
11762306a36Sopenharmony_ci				     : "0"(edi), "1"(esi)
11862306a36Sopenharmony_ci				     : "memory");
11962306a36Sopenharmony_ci	}
12062306a36Sopenharmony_ci	switch (n % 4) {
12162306a36Sopenharmony_ci		/* tail */
12262306a36Sopenharmony_ci	case 0:
12362306a36Sopenharmony_ci		return to;
12462306a36Sopenharmony_ci	case 1:
12562306a36Sopenharmony_ci		asm volatile("movsb"
12662306a36Sopenharmony_ci			     : "=&D"(edi), "=&S"(esi)
12762306a36Sopenharmony_ci			     : "0"(edi), "1"(esi)
12862306a36Sopenharmony_ci			     : "memory");
12962306a36Sopenharmony_ci		return to;
13062306a36Sopenharmony_ci	case 2:
13162306a36Sopenharmony_ci		asm volatile("movsw"
13262306a36Sopenharmony_ci			     : "=&D"(edi), "=&S"(esi)
13362306a36Sopenharmony_ci			     : "0"(edi), "1"(esi)
13462306a36Sopenharmony_ci			     : "memory");
13562306a36Sopenharmony_ci		return to;
13662306a36Sopenharmony_ci	default:
13762306a36Sopenharmony_ci		asm volatile("movsw\n\tmovsb"
13862306a36Sopenharmony_ci			     : "=&D"(edi), "=&S"(esi)
13962306a36Sopenharmony_ci			     : "0"(edi), "1"(esi)
14062306a36Sopenharmony_ci			     : "memory");
14162306a36Sopenharmony_ci		return to;
14262306a36Sopenharmony_ci	}
14362306a36Sopenharmony_ci}
14462306a36Sopenharmony_ci
14562306a36Sopenharmony_ci#define __HAVE_ARCH_MEMCPY
14662306a36Sopenharmony_ciextern void *memcpy(void *, const void *, size_t);
14762306a36Sopenharmony_ci
14862306a36Sopenharmony_ci#ifndef CONFIG_FORTIFY_SOURCE
14962306a36Sopenharmony_ci
15062306a36Sopenharmony_ci#define memcpy(t, f, n) __builtin_memcpy(t, f, n)
15162306a36Sopenharmony_ci
15262306a36Sopenharmony_ci#endif /* !CONFIG_FORTIFY_SOURCE */
15362306a36Sopenharmony_ci
15462306a36Sopenharmony_ci#define __HAVE_ARCH_MEMMOVE
15562306a36Sopenharmony_civoid *memmove(void *dest, const void *src, size_t n);
15662306a36Sopenharmony_ci
15762306a36Sopenharmony_ciextern int memcmp(const void *, const void *, size_t);
15862306a36Sopenharmony_ci#ifndef CONFIG_FORTIFY_SOURCE
15962306a36Sopenharmony_ci#define memcmp __builtin_memcmp
16062306a36Sopenharmony_ci#endif
16162306a36Sopenharmony_ci
16262306a36Sopenharmony_ci#define __HAVE_ARCH_MEMCHR
16362306a36Sopenharmony_ciextern void *memchr(const void *cs, int c, size_t count);
16462306a36Sopenharmony_ci
16562306a36Sopenharmony_cistatic inline void *__memset_generic(void *s, char c, size_t count)
16662306a36Sopenharmony_ci{
16762306a36Sopenharmony_ci	int d0, d1;
16862306a36Sopenharmony_ci	asm volatile("rep\n\t"
16962306a36Sopenharmony_ci		     "stosb"
17062306a36Sopenharmony_ci		     : "=&c" (d0), "=&D" (d1)
17162306a36Sopenharmony_ci		     : "a" (c), "1" (s), "0" (count)
17262306a36Sopenharmony_ci		     : "memory");
17362306a36Sopenharmony_ci	return s;
17462306a36Sopenharmony_ci}
17562306a36Sopenharmony_ci
17662306a36Sopenharmony_ci/* we might want to write optimized versions of these later */
17762306a36Sopenharmony_ci#define __constant_count_memset(s, c, count) __memset_generic((s), (c), (count))
17862306a36Sopenharmony_ci
17962306a36Sopenharmony_ci/* Added by Gertjan van Wingerde to make minix and sysv module work */
18062306a36Sopenharmony_ci#define __HAVE_ARCH_STRNLEN
18162306a36Sopenharmony_ciextern size_t strnlen(const char *s, size_t count);
18262306a36Sopenharmony_ci/* end of additional stuff */
18362306a36Sopenharmony_ci
18462306a36Sopenharmony_ci#define __HAVE_ARCH_STRSTR
18562306a36Sopenharmony_ciextern char *strstr(const char *cs, const char *ct);
18662306a36Sopenharmony_ci
18762306a36Sopenharmony_ci#define __memset(s, c, count)				\
18862306a36Sopenharmony_ci	(__builtin_constant_p(count)			\
18962306a36Sopenharmony_ci	 ? __constant_count_memset((s), (c), (count))	\
19062306a36Sopenharmony_ci	 : __memset_generic((s), (c), (count)))
19162306a36Sopenharmony_ci
19262306a36Sopenharmony_ci#define __HAVE_ARCH_MEMSET
19362306a36Sopenharmony_ciextern void *memset(void *, int, size_t);
19462306a36Sopenharmony_ci#ifndef CONFIG_FORTIFY_SOURCE
19562306a36Sopenharmony_ci#define memset(s, c, count) __builtin_memset(s, c, count)
19662306a36Sopenharmony_ci#endif /* !CONFIG_FORTIFY_SOURCE */
19762306a36Sopenharmony_ci
19862306a36Sopenharmony_ci#define __HAVE_ARCH_MEMSET16
19962306a36Sopenharmony_cistatic inline void *memset16(uint16_t *s, uint16_t v, size_t n)
20062306a36Sopenharmony_ci{
20162306a36Sopenharmony_ci	int d0, d1;
20262306a36Sopenharmony_ci	asm volatile("rep\n\t"
20362306a36Sopenharmony_ci		     "stosw"
20462306a36Sopenharmony_ci		     : "=&c" (d0), "=&D" (d1)
20562306a36Sopenharmony_ci		     : "a" (v), "1" (s), "0" (n)
20662306a36Sopenharmony_ci		     : "memory");
20762306a36Sopenharmony_ci	return s;
20862306a36Sopenharmony_ci}
20962306a36Sopenharmony_ci
21062306a36Sopenharmony_ci#define __HAVE_ARCH_MEMSET32
21162306a36Sopenharmony_cistatic inline void *memset32(uint32_t *s, uint32_t v, size_t n)
21262306a36Sopenharmony_ci{
21362306a36Sopenharmony_ci	int d0, d1;
21462306a36Sopenharmony_ci	asm volatile("rep\n\t"
21562306a36Sopenharmony_ci		     "stosl"
21662306a36Sopenharmony_ci		     : "=&c" (d0), "=&D" (d1)
21762306a36Sopenharmony_ci		     : "a" (v), "1" (s), "0" (n)
21862306a36Sopenharmony_ci		     : "memory");
21962306a36Sopenharmony_ci	return s;
22062306a36Sopenharmony_ci}
22162306a36Sopenharmony_ci
22262306a36Sopenharmony_ci/*
22362306a36Sopenharmony_ci * find the first occurrence of byte 'c', or 1 past the area if none
22462306a36Sopenharmony_ci */
22562306a36Sopenharmony_ci#define __HAVE_ARCH_MEMSCAN
22662306a36Sopenharmony_ciextern void *memscan(void *addr, int c, size_t size);
22762306a36Sopenharmony_ci
22862306a36Sopenharmony_ci#endif /* __KERNEL__ */
22962306a36Sopenharmony_ci
23062306a36Sopenharmony_ci#endif /* _ASM_X86_STRING_32_H */
231