1*b6cbf720SGianluca Guida /*- 2*b6cbf720SGianluca Guida * Copyright (c) 2009 The NetBSD Foundation, Inc. 3*b6cbf720SGianluca Guida * All rights reserved. 4*b6cbf720SGianluca Guida * 5*b6cbf720SGianluca Guida * This code is derived from software contributed to The NetBSD Foundation 6*b6cbf720SGianluca Guida * by Matt Thomas <matt@3am-software.com>. 7*b6cbf720SGianluca Guida * 8*b6cbf720SGianluca Guida * Redistribution and use in source and binary forms, with or without 9*b6cbf720SGianluca Guida * modification, are permitted provided that the following conditions 10*b6cbf720SGianluca Guida * are met: 11*b6cbf720SGianluca Guida * 1. Redistributions of source code must retain the above copyright 12*b6cbf720SGianluca Guida * notice, this list of conditions and the following disclaimer. 13*b6cbf720SGianluca Guida * 2. Redistributions in binary form must reproduce the above copyright 14*b6cbf720SGianluca Guida * notice, this list of conditions and the following disclaimer in the 15*b6cbf720SGianluca Guida * documentation and/or other materials provided with the distribution. 16*b6cbf720SGianluca Guida * 17*b6cbf720SGianluca Guida * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 18*b6cbf720SGianluca Guida * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 19*b6cbf720SGianluca Guida * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 20*b6cbf720SGianluca Guida * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 21*b6cbf720SGianluca Guida * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22*b6cbf720SGianluca Guida * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 23*b6cbf720SGianluca Guida * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 24*b6cbf720SGianluca Guida * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 25*b6cbf720SGianluca Guida * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 26*b6cbf720SGianluca Guida * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 27*b6cbf720SGianluca Guida * POSSIBILITY OF SUCH DAMAGE. 28*b6cbf720SGianluca Guida */ 29*b6cbf720SGianluca Guida 30*b6cbf720SGianluca Guida #include <sys/types.h> 31*b6cbf720SGianluca Guida 32*b6cbf720SGianluca Guida #if !defined(_KERNEL) && !defined(_STANDALONE) 33*b6cbf720SGianluca Guida #include <assert.h> 34*b6cbf720SGianluca Guida #include <limits.h> 35*b6cbf720SGianluca Guida #include <string.h> 36*b6cbf720SGianluca Guida #include <inttypes.h> 37*b6cbf720SGianluca Guida #else 38*b6cbf720SGianluca Guida #include <lib/libkern/libkern.h> 39*b6cbf720SGianluca Guida #include <machine/limits.h> 40*b6cbf720SGianluca Guida #endif 41*b6cbf720SGianluca Guida 42*b6cbf720SGianluca Guida #include <sys/endian.h> 43*b6cbf720SGianluca Guida #include <machine/types.h> 44*b6cbf720SGianluca Guida 45*b6cbf720SGianluca Guida #ifdef TEST 46*b6cbf720SGianluca Guida #include <assert.h> 47*b6cbf720SGianluca Guida #define _DIAGASSERT(a) assert(a) 48*b6cbf720SGianluca Guida #endif 49*b6cbf720SGianluca Guida 50*b6cbf720SGianluca Guida #ifdef _FORTIFY_SOURCE 51*b6cbf720SGianluca Guida #undef bzero 52*b6cbf720SGianluca Guida #undef memset 53*b6cbf720SGianluca Guida #endif 54*b6cbf720SGianluca Guida 55*b6cbf720SGianluca Guida #if defined(LIBC_SCCS) && !defined(lint) 56*b6cbf720SGianluca Guida __RCSID("$NetBSD: memset2.c,v 1.2 2009/12/14 00:39:01 matt Exp $"); 57*b6cbf720SGianluca Guida #endif /* LIBC_SCCS and not lint */ 58*b6cbf720SGianluca Guida 59*b6cbf720SGianluca Guida /* 60*b6cbf720SGianluca Guida * Assume uregister_t is the widest non-synthetic unsigned type. 61*b6cbf720SGianluca Guida */ 62*b6cbf720SGianluca Guida typedef uregister_t memword_t; 63*b6cbf720SGianluca Guida 64*b6cbf720SGianluca Guida #ifdef BZERO 65*b6cbf720SGianluca Guida static inline 66*b6cbf720SGianluca Guida #define memset memset0 67*b6cbf720SGianluca Guida #endif 68*b6cbf720SGianluca Guida 69*b6cbf720SGianluca Guida #ifdef TEST 70*b6cbf720SGianluca Guida static 71*b6cbf720SGianluca Guida #define memset test_memset 72*b6cbf720SGianluca Guida #endif 73*b6cbf720SGianluca Guida 74*b6cbf720SGianluca Guida #ifdef CTASSERT 75*b6cbf720SGianluca Guida CTASSERT((~(memword_t)0U >> 1) != ~(memword_t)0U); 76*b6cbf720SGianluca Guida #endif 77*b6cbf720SGianluca Guida 78*b6cbf720SGianluca Guida void * 79*b6cbf720SGianluca Guida memset(void *addr, int c, size_t len) 80*b6cbf720SGianluca Guida { 81*b6cbf720SGianluca Guida memword_t *dstp = addr; 82*b6cbf720SGianluca Guida memword_t *edstp; 83*b6cbf720SGianluca Guida memword_t fill; 84*b6cbf720SGianluca Guida #ifndef __OPTIMIZE_SIZE__ 85*b6cbf720SGianluca Guida memword_t keep_mask = 0; 86*b6cbf720SGianluca Guida #endif 87*b6cbf720SGianluca Guida size_t fill_count; 88*b6cbf720SGianluca Guida 89*b6cbf720SGianluca Guida _DIAGASSERT(addr != 0); 90*b6cbf720SGianluca Guida 91*b6cbf720SGianluca Guida if (__predict_false(len == 0)) 92*b6cbf720SGianluca Guida return addr; 93*b6cbf720SGianluca Guida 94*b6cbf720SGianluca Guida /* 95*b6cbf720SGianluca Guida * Pad out the fill byte (v) across a memword_t. 96*b6cbf720SGianluca Guida * The conditional at the end prevents GCC from complaing about 97*b6cbf720SGianluca Guida * shift count >= width of type 98*b6cbf720SGianluca Guida */ 99*b6cbf720SGianluca Guida fill = c; 100*b6cbf720SGianluca Guida fill |= fill << 8; 101*b6cbf720SGianluca Guida fill |= fill << 16; 102*b6cbf720SGianluca Guida fill |= fill << (sizeof(c) < sizeof(fill) ? 32 : 0); 103*b6cbf720SGianluca Guida 104*b6cbf720SGianluca Guida /* 105*b6cbf720SGianluca Guida * Get the number of unaligned bytes to fill in the first word. 106*b6cbf720SGianluca Guida */ 107*b6cbf720SGianluca Guida fill_count = -(uintptr_t)addr & (sizeof(memword_t) - 1); 108*b6cbf720SGianluca Guida 109*b6cbf720SGianluca Guida if (__predict_false(fill_count != 0)) { 110*b6cbf720SGianluca Guida #ifndef __OPTIMIZE_SIZE__ 111*b6cbf720SGianluca Guida /* 112*b6cbf720SGianluca Guida * We want to clear <fill_count> trailing bytes in the word. 113*b6cbf720SGianluca Guida * On big/little endian, these are the least/most significant, 114*b6cbf720SGianluca Guida * bits respectively. So as we shift, the keep_mask will only 115*b6cbf720SGianluca Guida * have bits set for the bytes we won't be filling. 116*b6cbf720SGianluca Guida */ 117*b6cbf720SGianluca Guida #if BYTE_ORDER == BIG_ENDIAN 118*b6cbf720SGianluca Guida keep_mask = ~(memword_t)0U << (fill_count * 8); 119*b6cbf720SGianluca Guida #endif 120*b6cbf720SGianluca Guida #if BYTE_ORDER == LITTLE_ENDIAN 121*b6cbf720SGianluca Guida keep_mask = ~(memword_t)0U >> (fill_count * 8); 122*b6cbf720SGianluca Guida #endif 123*b6cbf720SGianluca Guida /* 124*b6cbf720SGianluca Guida * Make sure dstp is aligned to a memword_t boundary. 125*b6cbf720SGianluca Guida */ 126*b6cbf720SGianluca Guida dstp = (memword_t *)((uintptr_t)addr & -sizeof(memword_t)); 127*b6cbf720SGianluca Guida if (len >= fill_count) { 128*b6cbf720SGianluca Guida /* 129*b6cbf720SGianluca Guida * If we can fill the rest of this word, then we mask 130*b6cbf720SGianluca Guida * off the bytes we are filling and then fill in those 131*b6cbf720SGianluca Guida * bytes with the new fill value. 132*b6cbf720SGianluca Guida */ 133*b6cbf720SGianluca Guida *dstp = (*dstp & keep_mask) | (fill & ~keep_mask); 134*b6cbf720SGianluca Guida len -= fill_count; 135*b6cbf720SGianluca Guida if (__predict_false(len == 0)) 136*b6cbf720SGianluca Guida return addr; 137*b6cbf720SGianluca Guida /* 138*b6cbf720SGianluca Guida * Since we were able to fill the rest of this word, 139*b6cbf720SGianluca Guida * we will advance to the next word and thus have no 140*b6cbf720SGianluca Guida * bytes to preserve. 141*b6cbf720SGianluca Guida * 142*b6cbf720SGianluca Guida * If we don't have enough to fill the rest of this 143*b6cbf720SGianluca Guida * word, we will fall through the following loop 144*b6cbf720SGianluca Guida * (since there are no full words to fill). Then we 145*b6cbf720SGianluca Guida * use the keep_mask above to preserve the leading 146*b6cbf720SGianluca Guida * bytes of word. 147*b6cbf720SGianluca Guida */ 148*b6cbf720SGianluca Guida dstp++; 149*b6cbf720SGianluca Guida keep_mask = 0; 150*b6cbf720SGianluca Guida } else { 151*b6cbf720SGianluca Guida len += (uintptr_t)addr & (sizeof(memword_t) - 1); 152*b6cbf720SGianluca Guida } 153*b6cbf720SGianluca Guida #else /* __OPTIMIZE_SIZE__ */ 154*b6cbf720SGianluca Guida uint8_t *dp, *ep; 155*b6cbf720SGianluca Guida if (len < fill_count) 156*b6cbf720SGianluca Guida fill_count = len; 157*b6cbf720SGianluca Guida for (dp = (uint8_t *)dstp, ep = dp + fill_count; 158*b6cbf720SGianluca Guida dp != ep; dp++) 159*b6cbf720SGianluca Guida *dp = fill; 160*b6cbf720SGianluca Guida if ((len -= fill_count) == 0) 161*b6cbf720SGianluca Guida return addr; 162*b6cbf720SGianluca Guida dstp = (memword_t *)ep; 163*b6cbf720SGianluca Guida #endif /* __OPTIMIZE_SIZE__ */ 164*b6cbf720SGianluca Guida } 165*b6cbf720SGianluca Guida 166*b6cbf720SGianluca Guida /* 167*b6cbf720SGianluca Guida * Simply fill memory one word at time (for as many full words we have 168*b6cbf720SGianluca Guida * to write). 169*b6cbf720SGianluca Guida */ 170*b6cbf720SGianluca Guida for (edstp = dstp + len / sizeof(memword_t); dstp != edstp; dstp++) 171*b6cbf720SGianluca Guida *dstp = fill; 172*b6cbf720SGianluca Guida 173*b6cbf720SGianluca Guida /* 174*b6cbf720SGianluca Guida * We didn't subtract out the full words we just filled since we know 175*b6cbf720SGianluca Guida * by the time we get here we will have less than a words worth to 176*b6cbf720SGianluca Guida * write. So we can concern ourselves with only the subword len bits. 177*b6cbf720SGianluca Guida */ 178*b6cbf720SGianluca Guida len &= sizeof(memword_t)-1; 179*b6cbf720SGianluca Guida if (len > 0) { 180*b6cbf720SGianluca Guida #ifndef __OPTIMIZE_SIZE__ 181*b6cbf720SGianluca Guida /* 182*b6cbf720SGianluca Guida * We want to clear <len> leading bytes in the word. 183*b6cbf720SGianluca Guida * On big/little endian, these are the most/least significant 184*b6cbf720SGianluca Guida * bits, respectively, But as we want the mask of the bytes to 185*b6cbf720SGianluca Guida * keep, we have to complement the mask. So after we shift, 186*b6cbf720SGianluca Guida * the keep_mask will only have bits set for the bytes we won't 187*b6cbf720SGianluca Guida * be filling. 188*b6cbf720SGianluca Guida * 189*b6cbf720SGianluca Guida * But the keep_mask could already have bytes to preserve 190*b6cbf720SGianluca Guida * if the amount to fill was less than the amount of traiing 191*b6cbf720SGianluca Guida * space in the first word. 192*b6cbf720SGianluca Guida */ 193*b6cbf720SGianluca Guida #if BYTE_ORDER == BIG_ENDIAN 194*b6cbf720SGianluca Guida keep_mask |= ~(memword_t)0U >> (len * 8); 195*b6cbf720SGianluca Guida #endif 196*b6cbf720SGianluca Guida #if BYTE_ORDER == LITTLE_ENDIAN 197*b6cbf720SGianluca Guida keep_mask |= ~(memword_t)0U << (len * 8); 198*b6cbf720SGianluca Guida #endif 199*b6cbf720SGianluca Guida /* 200*b6cbf720SGianluca Guida * Now we mask off the bytes we are filling and then fill in 201*b6cbf720SGianluca Guida * those bytes with the new fill value. 202*b6cbf720SGianluca Guida */ 203*b6cbf720SGianluca Guida *dstp = (*dstp & keep_mask) | (fill & ~keep_mask); 204*b6cbf720SGianluca Guida #else /* __OPTIMIZE_SIZE__ */ 205*b6cbf720SGianluca Guida uint8_t *dp, *ep; 206*b6cbf720SGianluca Guida for (dp = (uint8_t *)dstp, ep = dp + len; 207*b6cbf720SGianluca Guida dp != ep; dp++) 208*b6cbf720SGianluca Guida *dp = fill; 209*b6cbf720SGianluca Guida #endif /* __OPTIMIZE_SIZE__ */ 210*b6cbf720SGianluca Guida } 211*b6cbf720SGianluca Guida 212*b6cbf720SGianluca Guida /* 213*b6cbf720SGianluca Guida * Return the initial addr 214*b6cbf720SGianluca Guida */ 215*b6cbf720SGianluca Guida return addr; 216*b6cbf720SGianluca Guida } 217*b6cbf720SGianluca Guida 218*b6cbf720SGianluca Guida #ifdef BZERO 219*b6cbf720SGianluca Guida /* 220*b6cbf720SGianluca Guida * For bzero, simply inline memset and let the compiler optimize things away. 221*b6cbf720SGianluca Guida */ 222*b6cbf720SGianluca Guida void 223*b6cbf720SGianluca Guida bzero(void *addr, size_t len) 224*b6cbf720SGianluca Guida { 225*b6cbf720SGianluca Guida memset(addr, 0, len); 226*b6cbf720SGianluca Guida } 227*b6cbf720SGianluca Guida #endif 228*b6cbf720SGianluca Guida 229*b6cbf720SGianluca Guida #ifdef TEST 230*b6cbf720SGianluca Guida #include <stdbool.h> 231*b6cbf720SGianluca Guida #include <stdio.h> 232*b6cbf720SGianluca Guida 233*b6cbf720SGianluca Guida #undef memset 234*b6cbf720SGianluca Guida 235*b6cbf720SGianluca Guida static union { 236*b6cbf720SGianluca Guida uint8_t bytes[sizeof(memword_t) * 4]; 237*b6cbf720SGianluca Guida memword_t words[4]; 238*b6cbf720SGianluca Guida } testmem; 239*b6cbf720SGianluca Guida 240*b6cbf720SGianluca Guida int 241*b6cbf720SGianluca Guida main(int argc, char **argv) 242*b6cbf720SGianluca Guida { 243*b6cbf720SGianluca Guida size_t start; 244*b6cbf720SGianluca Guida size_t len; 245*b6cbf720SGianluca Guida bool failed = false; 246*b6cbf720SGianluca Guida 247*b6cbf720SGianluca Guida for (start = 1; start < sizeof(testmem) - 1; start++) { 248*b6cbf720SGianluca Guida for (len = 1; start + len < sizeof(testmem) - 1; len++) { 249*b6cbf720SGianluca Guida bool ok = true; 250*b6cbf720SGianluca Guida size_t i; 251*b6cbf720SGianluca Guida uint8_t check_value; 252*b6cbf720SGianluca Guida memset(testmem.bytes, 0xff, sizeof(testmem)); 253*b6cbf720SGianluca Guida test_memset(testmem.bytes + start, 0x00, len); 254*b6cbf720SGianluca Guida for (i = 0; i < sizeof(testmem); i++) { 255*b6cbf720SGianluca Guida if (i == 0 || i == start + len) 256*b6cbf720SGianluca Guida check_value = 0xff; 257*b6cbf720SGianluca Guida else if (i == start) 258*b6cbf720SGianluca Guida check_value = 0x00; 259*b6cbf720SGianluca Guida if (testmem.bytes[i] != check_value) { 260*b6cbf720SGianluca Guida if (ok) 261*b6cbf720SGianluca Guida printf("pass @ %zu .. %zu failed", 262*b6cbf720SGianluca Guida start, start + len - 1); 263*b6cbf720SGianluca Guida ok = false; 264*b6cbf720SGianluca Guida printf(" [%zu]=0x%02x(!0x%02x)", 265*b6cbf720SGianluca Guida i, testmem.bytes[i], check_value); 266*b6cbf720SGianluca Guida } 267*b6cbf720SGianluca Guida } 268*b6cbf720SGianluca Guida if (!ok) { 269*b6cbf720SGianluca Guida printf("\n"); 270*b6cbf720SGianluca Guida failed = 1; 271*b6cbf720SGianluca Guida } 272*b6cbf720SGianluca Guida } 273*b6cbf720SGianluca Guida } 274*b6cbf720SGianluca Guida 275*b6cbf720SGianluca Guida return failed ? 1 : 0; 276*b6cbf720SGianluca Guida } 277*b6cbf720SGianluca Guida #endif /* TEST */ 278