18c2ecf20Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 */
28c2ecf20Sopenharmony_ci#ifndef _ASM_X86_STRING_32_H
38c2ecf20Sopenharmony_ci#define _ASM_X86_STRING_32_H
48c2ecf20Sopenharmony_ci
58c2ecf20Sopenharmony_ci#ifdef __KERNEL__
68c2ecf20Sopenharmony_ci
78c2ecf20Sopenharmony_ci/* Let gcc decide whether to inline or use the out of line functions */
88c2ecf20Sopenharmony_ci
98c2ecf20Sopenharmony_ci#define __HAVE_ARCH_STRCPY
108c2ecf20Sopenharmony_ciextern char *strcpy(char *dest, const char *src);
118c2ecf20Sopenharmony_ci
128c2ecf20Sopenharmony_ci#define __HAVE_ARCH_STRNCPY
138c2ecf20Sopenharmony_ciextern char *strncpy(char *dest, const char *src, size_t count);
148c2ecf20Sopenharmony_ci
158c2ecf20Sopenharmony_ci#define __HAVE_ARCH_STRCAT
168c2ecf20Sopenharmony_ciextern char *strcat(char *dest, const char *src);
178c2ecf20Sopenharmony_ci
188c2ecf20Sopenharmony_ci#define __HAVE_ARCH_STRNCAT
198c2ecf20Sopenharmony_ciextern char *strncat(char *dest, const char *src, size_t count);
208c2ecf20Sopenharmony_ci
218c2ecf20Sopenharmony_ci#define __HAVE_ARCH_STRCMP
228c2ecf20Sopenharmony_ciextern int strcmp(const char *cs, const char *ct);
238c2ecf20Sopenharmony_ci
248c2ecf20Sopenharmony_ci#define __HAVE_ARCH_STRNCMP
258c2ecf20Sopenharmony_ciextern int strncmp(const char *cs, const char *ct, size_t count);
268c2ecf20Sopenharmony_ci
278c2ecf20Sopenharmony_ci#define __HAVE_ARCH_STRCHR
288c2ecf20Sopenharmony_ciextern char *strchr(const char *s, int c);
298c2ecf20Sopenharmony_ci
308c2ecf20Sopenharmony_ci#define __HAVE_ARCH_STRLEN
318c2ecf20Sopenharmony_ciextern size_t strlen(const char *s);
328c2ecf20Sopenharmony_ci
338c2ecf20Sopenharmony_cistatic __always_inline void *__memcpy(void *to, const void *from, size_t n)
348c2ecf20Sopenharmony_ci{
358c2ecf20Sopenharmony_ci	int d0, d1, d2;
368c2ecf20Sopenharmony_ci	asm volatile("rep ; movsl\n\t"
378c2ecf20Sopenharmony_ci		     "movl %4,%%ecx\n\t"
388c2ecf20Sopenharmony_ci		     "andl $3,%%ecx\n\t"
398c2ecf20Sopenharmony_ci		     "jz 1f\n\t"
408c2ecf20Sopenharmony_ci		     "rep ; movsb\n\t"
418c2ecf20Sopenharmony_ci		     "1:"
428c2ecf20Sopenharmony_ci		     : "=&c" (d0), "=&D" (d1), "=&S" (d2)
438c2ecf20Sopenharmony_ci		     : "0" (n / 4), "g" (n), "1" ((long)to), "2" ((long)from)
448c2ecf20Sopenharmony_ci		     : "memory");
458c2ecf20Sopenharmony_ci	return to;
468c2ecf20Sopenharmony_ci}
478c2ecf20Sopenharmony_ci
488c2ecf20Sopenharmony_ci/*
498c2ecf20Sopenharmony_ci * This looks ugly, but the compiler can optimize it totally,
508c2ecf20Sopenharmony_ci * as the count is constant.
518c2ecf20Sopenharmony_ci */
528c2ecf20Sopenharmony_cistatic __always_inline void *__constant_memcpy(void *to, const void *from,
538c2ecf20Sopenharmony_ci					       size_t n)
548c2ecf20Sopenharmony_ci{
558c2ecf20Sopenharmony_ci	long esi, edi;
568c2ecf20Sopenharmony_ci	if (!n)
578c2ecf20Sopenharmony_ci		return to;
588c2ecf20Sopenharmony_ci
598c2ecf20Sopenharmony_ci	switch (n) {
608c2ecf20Sopenharmony_ci	case 1:
618c2ecf20Sopenharmony_ci		*(char *)to = *(char *)from;
628c2ecf20Sopenharmony_ci		return to;
638c2ecf20Sopenharmony_ci	case 2:
648c2ecf20Sopenharmony_ci		*(short *)to = *(short *)from;
658c2ecf20Sopenharmony_ci		return to;
668c2ecf20Sopenharmony_ci	case 4:
678c2ecf20Sopenharmony_ci		*(int *)to = *(int *)from;
688c2ecf20Sopenharmony_ci		return to;
698c2ecf20Sopenharmony_ci	case 3:
708c2ecf20Sopenharmony_ci		*(short *)to = *(short *)from;
718c2ecf20Sopenharmony_ci		*((char *)to + 2) = *((char *)from + 2);
728c2ecf20Sopenharmony_ci		return to;
738c2ecf20Sopenharmony_ci	case 5:
748c2ecf20Sopenharmony_ci		*(int *)to = *(int *)from;
758c2ecf20Sopenharmony_ci		*((char *)to + 4) = *((char *)from + 4);
768c2ecf20Sopenharmony_ci		return to;
778c2ecf20Sopenharmony_ci	case 6:
788c2ecf20Sopenharmony_ci		*(int *)to = *(int *)from;
798c2ecf20Sopenharmony_ci		*((short *)to + 2) = *((short *)from + 2);
808c2ecf20Sopenharmony_ci		return to;
818c2ecf20Sopenharmony_ci	case 8:
828c2ecf20Sopenharmony_ci		*(int *)to = *(int *)from;
838c2ecf20Sopenharmony_ci		*((int *)to + 1) = *((int *)from + 1);
848c2ecf20Sopenharmony_ci		return to;
858c2ecf20Sopenharmony_ci	}
868c2ecf20Sopenharmony_ci
878c2ecf20Sopenharmony_ci	esi = (long)from;
888c2ecf20Sopenharmony_ci	edi = (long)to;
898c2ecf20Sopenharmony_ci	if (n >= 5 * 4) {
908c2ecf20Sopenharmony_ci		/* large block: use rep prefix */
918c2ecf20Sopenharmony_ci		int ecx;
928c2ecf20Sopenharmony_ci		asm volatile("rep ; movsl"
938c2ecf20Sopenharmony_ci			     : "=&c" (ecx), "=&D" (edi), "=&S" (esi)
948c2ecf20Sopenharmony_ci			     : "0" (n / 4), "1" (edi), "2" (esi)
958c2ecf20Sopenharmony_ci			     : "memory"
968c2ecf20Sopenharmony_ci		);
978c2ecf20Sopenharmony_ci	} else {
988c2ecf20Sopenharmony_ci		/* small block: don't clobber ecx + smaller code */
998c2ecf20Sopenharmony_ci		if (n >= 4 * 4)
1008c2ecf20Sopenharmony_ci			asm volatile("movsl"
1018c2ecf20Sopenharmony_ci				     : "=&D"(edi), "=&S"(esi)
1028c2ecf20Sopenharmony_ci				     : "0"(edi), "1"(esi)
1038c2ecf20Sopenharmony_ci				     : "memory");
1048c2ecf20Sopenharmony_ci		if (n >= 3 * 4)
1058c2ecf20Sopenharmony_ci			asm volatile("movsl"
1068c2ecf20Sopenharmony_ci				     : "=&D"(edi), "=&S"(esi)
1078c2ecf20Sopenharmony_ci				     : "0"(edi), "1"(esi)
1088c2ecf20Sopenharmony_ci				     : "memory");
1098c2ecf20Sopenharmony_ci		if (n >= 2 * 4)
1108c2ecf20Sopenharmony_ci			asm volatile("movsl"
1118c2ecf20Sopenharmony_ci				     : "=&D"(edi), "=&S"(esi)
1128c2ecf20Sopenharmony_ci				     : "0"(edi), "1"(esi)
1138c2ecf20Sopenharmony_ci				     : "memory");
1148c2ecf20Sopenharmony_ci		if (n >= 1 * 4)
1158c2ecf20Sopenharmony_ci			asm volatile("movsl"
1168c2ecf20Sopenharmony_ci				     : "=&D"(edi), "=&S"(esi)
1178c2ecf20Sopenharmony_ci				     : "0"(edi), "1"(esi)
1188c2ecf20Sopenharmony_ci				     : "memory");
1198c2ecf20Sopenharmony_ci	}
1208c2ecf20Sopenharmony_ci	switch (n % 4) {
1218c2ecf20Sopenharmony_ci		/* tail */
1228c2ecf20Sopenharmony_ci	case 0:
1238c2ecf20Sopenharmony_ci		return to;
1248c2ecf20Sopenharmony_ci	case 1:
1258c2ecf20Sopenharmony_ci		asm volatile("movsb"
1268c2ecf20Sopenharmony_ci			     : "=&D"(edi), "=&S"(esi)
1278c2ecf20Sopenharmony_ci			     : "0"(edi), "1"(esi)
1288c2ecf20Sopenharmony_ci			     : "memory");
1298c2ecf20Sopenharmony_ci		return to;
1308c2ecf20Sopenharmony_ci	case 2:
1318c2ecf20Sopenharmony_ci		asm volatile("movsw"
1328c2ecf20Sopenharmony_ci			     : "=&D"(edi), "=&S"(esi)
1338c2ecf20Sopenharmony_ci			     : "0"(edi), "1"(esi)
1348c2ecf20Sopenharmony_ci			     : "memory");
1358c2ecf20Sopenharmony_ci		return to;
1368c2ecf20Sopenharmony_ci	default:
1378c2ecf20Sopenharmony_ci		asm volatile("movsw\n\tmovsb"
1388c2ecf20Sopenharmony_ci			     : "=&D"(edi), "=&S"(esi)
1398c2ecf20Sopenharmony_ci			     : "0"(edi), "1"(esi)
1408c2ecf20Sopenharmony_ci			     : "memory");
1418c2ecf20Sopenharmony_ci		return to;
1428c2ecf20Sopenharmony_ci	}
1438c2ecf20Sopenharmony_ci}
1448c2ecf20Sopenharmony_ci
1458c2ecf20Sopenharmony_ci#define __HAVE_ARCH_MEMCPY
1468c2ecf20Sopenharmony_ciextern void *memcpy(void *, const void *, size_t);
1478c2ecf20Sopenharmony_ci
1488c2ecf20Sopenharmony_ci#ifndef CONFIG_FORTIFY_SOURCE
1498c2ecf20Sopenharmony_ci#ifdef CONFIG_X86_USE_3DNOW
1508c2ecf20Sopenharmony_ci
1518c2ecf20Sopenharmony_ci#include <asm/mmx.h>
1528c2ecf20Sopenharmony_ci
1538c2ecf20Sopenharmony_ci/*
1548c2ecf20Sopenharmony_ci *	This CPU favours 3DNow strongly (eg AMD Athlon)
1558c2ecf20Sopenharmony_ci */
1568c2ecf20Sopenharmony_ci
1578c2ecf20Sopenharmony_cistatic inline void *__constant_memcpy3d(void *to, const void *from, size_t len)
1588c2ecf20Sopenharmony_ci{
1598c2ecf20Sopenharmony_ci	if (len < 512)
1608c2ecf20Sopenharmony_ci		return __constant_memcpy(to, from, len);
1618c2ecf20Sopenharmony_ci	return _mmx_memcpy(to, from, len);
1628c2ecf20Sopenharmony_ci}
1638c2ecf20Sopenharmony_ci
1648c2ecf20Sopenharmony_cistatic inline void *__memcpy3d(void *to, const void *from, size_t len)
1658c2ecf20Sopenharmony_ci{
1668c2ecf20Sopenharmony_ci	if (len < 512)
1678c2ecf20Sopenharmony_ci		return __memcpy(to, from, len);
1688c2ecf20Sopenharmony_ci	return _mmx_memcpy(to, from, len);
1698c2ecf20Sopenharmony_ci}
1708c2ecf20Sopenharmony_ci
1718c2ecf20Sopenharmony_ci#define memcpy(t, f, n)				\
1728c2ecf20Sopenharmony_ci	(__builtin_constant_p((n))		\
1738c2ecf20Sopenharmony_ci	 ? __constant_memcpy3d((t), (f), (n))	\
1748c2ecf20Sopenharmony_ci	 : __memcpy3d((t), (f), (n)))
1758c2ecf20Sopenharmony_ci
1768c2ecf20Sopenharmony_ci#else
1778c2ecf20Sopenharmony_ci
1788c2ecf20Sopenharmony_ci/*
1798c2ecf20Sopenharmony_ci *	No 3D Now!
1808c2ecf20Sopenharmony_ci */
1818c2ecf20Sopenharmony_ci
1828c2ecf20Sopenharmony_ci#define memcpy(t, f, n) __builtin_memcpy(t, f, n)
1838c2ecf20Sopenharmony_ci
1848c2ecf20Sopenharmony_ci#endif
1858c2ecf20Sopenharmony_ci#endif /* !CONFIG_FORTIFY_SOURCE */
1868c2ecf20Sopenharmony_ci
1878c2ecf20Sopenharmony_ci#define __HAVE_ARCH_MEMMOVE
1888c2ecf20Sopenharmony_civoid *memmove(void *dest, const void *src, size_t n);
1898c2ecf20Sopenharmony_ci
1908c2ecf20Sopenharmony_ciextern int memcmp(const void *, const void *, size_t);
1918c2ecf20Sopenharmony_ci#ifndef CONFIG_FORTIFY_SOURCE
1928c2ecf20Sopenharmony_ci#define memcmp __builtin_memcmp
1938c2ecf20Sopenharmony_ci#endif
1948c2ecf20Sopenharmony_ci
1958c2ecf20Sopenharmony_ci#define __HAVE_ARCH_MEMCHR
1968c2ecf20Sopenharmony_ciextern void *memchr(const void *cs, int c, size_t count);
1978c2ecf20Sopenharmony_ci
1988c2ecf20Sopenharmony_cistatic inline void *__memset_generic(void *s, char c, size_t count)
1998c2ecf20Sopenharmony_ci{
2008c2ecf20Sopenharmony_ci	int d0, d1;
2018c2ecf20Sopenharmony_ci	asm volatile("rep\n\t"
2028c2ecf20Sopenharmony_ci		     "stosb"
2038c2ecf20Sopenharmony_ci		     : "=&c" (d0), "=&D" (d1)
2048c2ecf20Sopenharmony_ci		     : "a" (c), "1" (s), "0" (count)
2058c2ecf20Sopenharmony_ci		     : "memory");
2068c2ecf20Sopenharmony_ci	return s;
2078c2ecf20Sopenharmony_ci}
2088c2ecf20Sopenharmony_ci
2098c2ecf20Sopenharmony_ci/* we might want to write optimized versions of these later */
2108c2ecf20Sopenharmony_ci#define __constant_count_memset(s, c, count) __memset_generic((s), (c), (count))
2118c2ecf20Sopenharmony_ci
2128c2ecf20Sopenharmony_ci/* Added by Gertjan van Wingerde to make minix and sysv module work */
2138c2ecf20Sopenharmony_ci#define __HAVE_ARCH_STRNLEN
2148c2ecf20Sopenharmony_ciextern size_t strnlen(const char *s, size_t count);
2158c2ecf20Sopenharmony_ci/* end of additional stuff */
2168c2ecf20Sopenharmony_ci
2178c2ecf20Sopenharmony_ci#define __HAVE_ARCH_STRSTR
2188c2ecf20Sopenharmony_ciextern char *strstr(const char *cs, const char *ct);
2198c2ecf20Sopenharmony_ci
2208c2ecf20Sopenharmony_ci#define __memset(s, c, count)				\
2218c2ecf20Sopenharmony_ci	(__builtin_constant_p(count)			\
2228c2ecf20Sopenharmony_ci	 ? __constant_count_memset((s), (c), (count))	\
2238c2ecf20Sopenharmony_ci	 : __memset_generic((s), (c), (count)))
2248c2ecf20Sopenharmony_ci
2258c2ecf20Sopenharmony_ci#define __HAVE_ARCH_MEMSET
2268c2ecf20Sopenharmony_ciextern void *memset(void *, int, size_t);
2278c2ecf20Sopenharmony_ci#ifndef CONFIG_FORTIFY_SOURCE
2288c2ecf20Sopenharmony_ci#define memset(s, c, count) __builtin_memset(s, c, count)
2298c2ecf20Sopenharmony_ci#endif /* !CONFIG_FORTIFY_SOURCE */
2308c2ecf20Sopenharmony_ci
2318c2ecf20Sopenharmony_ci#define __HAVE_ARCH_MEMSET16
2328c2ecf20Sopenharmony_cistatic inline void *memset16(uint16_t *s, uint16_t v, size_t n)
2338c2ecf20Sopenharmony_ci{
2348c2ecf20Sopenharmony_ci	int d0, d1;
2358c2ecf20Sopenharmony_ci	asm volatile("rep\n\t"
2368c2ecf20Sopenharmony_ci		     "stosw"
2378c2ecf20Sopenharmony_ci		     : "=&c" (d0), "=&D" (d1)
2388c2ecf20Sopenharmony_ci		     : "a" (v), "1" (s), "0" (n)
2398c2ecf20Sopenharmony_ci		     : "memory");
2408c2ecf20Sopenharmony_ci	return s;
2418c2ecf20Sopenharmony_ci}
2428c2ecf20Sopenharmony_ci
2438c2ecf20Sopenharmony_ci#define __HAVE_ARCH_MEMSET32
2448c2ecf20Sopenharmony_cistatic inline void *memset32(uint32_t *s, uint32_t v, size_t n)
2458c2ecf20Sopenharmony_ci{
2468c2ecf20Sopenharmony_ci	int d0, d1;
2478c2ecf20Sopenharmony_ci	asm volatile("rep\n\t"
2488c2ecf20Sopenharmony_ci		     "stosl"
2498c2ecf20Sopenharmony_ci		     : "=&c" (d0), "=&D" (d1)
2508c2ecf20Sopenharmony_ci		     : "a" (v), "1" (s), "0" (n)
2518c2ecf20Sopenharmony_ci		     : "memory");
2528c2ecf20Sopenharmony_ci	return s;
2538c2ecf20Sopenharmony_ci}
2548c2ecf20Sopenharmony_ci
2558c2ecf20Sopenharmony_ci/*
2568c2ecf20Sopenharmony_ci * find the first occurrence of byte 'c', or 1 past the area if none
2578c2ecf20Sopenharmony_ci */
2588c2ecf20Sopenharmony_ci#define __HAVE_ARCH_MEMSCAN
2598c2ecf20Sopenharmony_ciextern void *memscan(void *addr, int c, size_t size);
2608c2ecf20Sopenharmony_ci
2618c2ecf20Sopenharmony_ci#endif /* __KERNEL__ */
2628c2ecf20Sopenharmony_ci
2638c2ecf20Sopenharmony_ci#endif /* _ASM_X86_STRING_32_H */
264