xref: /aosp_15_r20/external/coreboot/src/arch/x86/memset.c (revision b9411a12aaaa7e1e6a6fb7c5e057f44ee179a49c)
1 /* SPDX-License-Identifier: GPL-2.0-or-later */
2 
3 /* From glibc-2.14, sysdeps/i386/memset.c */
4 
5 #include <string.h>
6 #include <stdint.h>
7 #include <stdbool.h>
8 #include <asan.h>
9 
10 typedef uint32_t op_t;
11 
memset(void * dstpp,int c,size_t len)12 void *memset(void *dstpp, int c, size_t len)
13 {
14 	int d0;
15 	unsigned long int dstp = (unsigned long int)dstpp;
16 
17 #if (ENV_SEPARATE_ROMSTAGE && CONFIG(ASAN_IN_ROMSTAGE)) || \
18 		(ENV_RAMSTAGE && CONFIG(ASAN_IN_RAMSTAGE))
19 	check_memory_region((unsigned long)dstpp, len, true, _RET_IP_);
20 #endif
21 
22 	/* This explicit register allocation improves code very much indeed. */
23 	register op_t x asm("ax");
24 
25 	x = (unsigned char)c;
26 
27 	/* Clear the direction flag, so filling will move forward.  */
28 	asm volatile("cld");
29 
30 	/* This threshold value is optimal.  */
31 	if (len >= 12) {
32 		/* Fill X with four copies of the char we want to fill with. */
33 		x |= (x << 8);
34 		x |= (x << 16);
35 
36 		/* Adjust LEN for the bytes handled in the first loop.  */
37 		len -= (-dstp) % sizeof(op_t);
38 
39 		/*
40 		 * There are at least some bytes to set. No need to test for
41 		 * LEN == 0 in this alignment loop.
42 		 */
43 
44 		/* Fill bytes until DSTP is aligned on a longword boundary. */
45 		asm volatile(
46 			"rep\n"
47 			"stosb" /* %0, %2, %3 */ :
48 			"=D" (dstp), "=c" (d0) :
49 			"0" (dstp), "1" ((-dstp) % sizeof(op_t)), "a" (x) :
50 			"memory");
51 
52 		/* Fill longwords.  */
53 		asm volatile(
54 			"rep\n"
55 			"stosl" /* %0, %2, %3 */ :
56 			"=D" (dstp), "=c" (d0) :
57 			"0" (dstp), "1" (len / sizeof(op_t)), "a" (x) :
58 			"memory");
59 		len %= sizeof(op_t);
60 	}
61 
62 	/* Write the last few bytes. */
63 	asm volatile(
64 		"rep\n"
65 		"stosb" /* %0, %2, %3 */ :
66 		"=D" (dstp), "=c" (d0) :
67 		"0" (dstp), "1" (len), "a" (x) :
68 		"memory");
69 
70 	return dstpp;
71 }
72