2 * Copyright (c) 2009 The NetBSD Foundation, Inc.
5 * This code is derived from software contributed to The NetBSD Foundation
6 * by Matt Thomas <matt@3am-software.com>.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
17 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
18 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
19 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
20 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
21 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27 * POSSIBILITY OF SUCH DAMAGE.
30 #include <sys/types.h>
32 #if !defined(_KERNEL) && !defined(_STANDALONE)
38 #include <lib/libkern/libkern.h>
39 #include <machine/limits.h>
42 #include <sys/endian.h>
43 #include <machine/types.h>
47 #define _DIAGASSERT(a) assert(a)
50 #ifdef _FORTIFY_SOURCE
55 #if defined(LIBC_SCCS) && !defined(lint)
56 __RCSID("$NetBSD: memset2.c,v 1.2 2009/12/14 00:39:01 matt Exp $");
57 #endif /* LIBC_SCCS and not lint */
60 * Assume uregister_t is the widest non-synthetic unsigned type.
62 typedef uregister_t memword_t
;
66 #define memset memset0
71 #define memset test_memset
75 CTASSERT((~(memword_t
)0U >> 1) != ~(memword_t
)0U);
79 memset(void *addr
, int c
, size_t len
)
81 memword_t
*dstp
= addr
;
84 #ifndef __OPTIMIZE_SIZE__
85 memword_t keep_mask
= 0;
89 _DIAGASSERT(addr
!= 0);
91 if (__predict_false(len
== 0))
95 * Pad out the fill byte (v) across a memword_t.
96 * The conditional at the end prevents GCC from complaing about
97 * shift count >= width of type
102 fill
|= fill
<< (sizeof(c
) < sizeof(fill
) ? 32 : 0);
105 * Get the number of unaligned bytes to fill in the first word.
107 fill_count
= -(uintptr_t)addr
& (sizeof(memword_t
) - 1);
109 if (__predict_false(fill_count
!= 0)) {
110 #ifndef __OPTIMIZE_SIZE__
112 * We want to clear <fill_count> trailing bytes in the word.
113 * On big/little endian, these are the least/most significant,
114 * bits respectively. So as we shift, the keep_mask will only
115 * have bits set for the bytes we won't be filling.
117 #if BYTE_ORDER == BIG_ENDIAN
118 keep_mask
= ~(memword_t
)0U << (fill_count
* 8);
120 #if BYTE_ORDER == LITTLE_ENDIAN
121 keep_mask
= ~(memword_t
)0U >> (fill_count
* 8);
124 * Make sure dstp is aligned to a memword_t boundary.
126 dstp
= (memword_t
*)((uintptr_t)addr
& -sizeof(memword_t
));
127 if (len
>= fill_count
) {
129 * If we can fill the rest of this word, then we mask
130 * off the bytes we are filling and then fill in those
131 * bytes with the new fill value.
133 *dstp
= (*dstp
& keep_mask
) | (fill
& ~keep_mask
);
135 if (__predict_false(len
== 0))
138 * Since we were able to fill the rest of this word,
139 * we will advance to the next word and thus have no
142 * If we don't have enough to fill the rest of this
143 * word, we will fall through the following loop
144 * (since there are no full words to fill). Then we
145 * use the keep_mask above to preserve the leading
151 len
+= (uintptr_t)addr
& (sizeof(memword_t
) - 1);
153 #else /* __OPTIMIZE_SIZE__ */
155 if (len
< fill_count
)
157 for (dp
= (uint8_t *)dstp
, ep
= dp
+ fill_count
;
160 if ((len
-= fill_count
) == 0)
162 dstp
= (memword_t
*)ep
;
163 #endif /* __OPTIMIZE_SIZE__ */
167 * Simply fill memory one word at time (for as many full words we have
170 for (edstp
= dstp
+ len
/ sizeof(memword_t
); dstp
!= edstp
; dstp
++)
174 * We didn't subtract out the full words we just filled since we know
175 * by the time we get here we will have less than a words worth to
176 * write. So we can concern ourselves with only the subword len bits.
178 len
&= sizeof(memword_t
)-1;
180 #ifndef __OPTIMIZE_SIZE__
182 * We want to clear <len> leading bytes in the word.
183 * On big/little endian, these are the most/least significant
184 * bits, respectively, But as we want the mask of the bytes to
185 * keep, we have to complement the mask. So after we shift,
186 * the keep_mask will only have bits set for the bytes we won't
189 * But the keep_mask could already have bytes to preserve
190 * if the amount to fill was less than the amount of traiing
191 * space in the first word.
193 #if BYTE_ORDER == BIG_ENDIAN
194 keep_mask
|= ~(memword_t
)0U >> (len
* 8);
196 #if BYTE_ORDER == LITTLE_ENDIAN
197 keep_mask
|= ~(memword_t
)0U << (len
* 8);
200 * Now we mask off the bytes we are filling and then fill in
201 * those bytes with the new fill value.
203 *dstp
= (*dstp
& keep_mask
) | (fill
& ~keep_mask
);
204 #else /* __OPTIMIZE_SIZE__ */
206 for (dp
= (uint8_t *)dstp
, ep
= dp
+ len
;
209 #endif /* __OPTIMIZE_SIZE__ */
213 * Return the initial addr
220 * For bzero, simply inline memset and let the compiler optimize things away.
223 bzero(void *addr
, size_t len
)
225 memset(addr
, 0, len
);
236 uint8_t bytes
[sizeof(memword_t
) * 4];
241 main(int argc
, char **argv
)
247 for (start
= 1; start
< sizeof(testmem
) - 1; start
++) {
248 for (len
= 1; start
+ len
< sizeof(testmem
) - 1; len
++) {
252 memset(testmem
.bytes
, 0xff, sizeof(testmem
));
253 test_memset(testmem
.bytes
+ start
, 0x00, len
);
254 for (i
= 0; i
< sizeof(testmem
); i
++) {
255 if (i
== 0 || i
== start
+ len
)
259 if (testmem
.bytes
[i
] != check_value
) {
261 printf("pass @ %zu .. %zu failed",
262 start
, start
+ len
- 1);
264 printf(" [%zu]=0x%02x(!0x%02x)",
265 i
, testmem
.bytes
[i
], check_value
);
275 return failed
? 1 : 0;