linux/arch/microblaze/lib/memmove.c
<<
>>
Prefs
   1/*
   2 * Copyright (C) 2008-2009 Michal Simek <monstr@monstr.eu>
   3 * Copyright (C) 2008-2009 PetaLogix
   4 * Copyright (C) 2007 John Williams
   5 *
   6 * Reasonably optimised generic C-code for memcpy on Microblaze
   7 * This is generic C code to do efficient, alignment-aware memmove.
   8 *
   9 * It is based on demo code originally Copyright 2001 by Intel Corp, taken from
  10 * http://www.embedded.com/showArticle.jhtml?articleID=19205567
  11 *
  12 * Attempts were made, unsuccessfully, to contact the original
  13 * author of this code (Michael Morrow, Intel).  Below is the original
  14 * copyright notice.
  15 *
  16 * This software has been developed by Intel Corporation.
  17 * Intel specifically disclaims all warranties, express or
  18 * implied, and all liability, including consequential and
  19 * other indirect damages, for the use of this program, including
  20 * liability for infringement of any proprietary rights,
  21 * and including the warranties of merchantability and fitness
  22 * for a particular purpose. Intel does not assume any
  23 * responsibility for and errors which may appear in this program
  24 * not any responsibility to update it.
  25 */
  26
  27#include <linux/export.h>
  28#include <linux/types.h>
  29#include <linux/stddef.h>
  30#include <linux/compiler.h>
  31#include <linux/string.h>
  32
  33#ifdef __HAVE_ARCH_MEMMOVE
  34#ifndef CONFIG_OPT_LIB_FUNCTION
  35void *memmove(void *v_dst, const void *v_src, __kernel_size_t c)
  36{
  37        const char *src = v_src;
  38        char *dst = v_dst;
  39
  40        if (!c)
  41                return v_dst;
  42
  43        /* Use memcpy when source is higher than dest */
  44        if (v_dst <= v_src)
  45                return memcpy(v_dst, v_src, c);
  46
  47        /* copy backwards, from end to beginning */
  48        src += c;
  49        dst += c;
  50
  51        /* Simple, byte oriented memmove. */
  52        while (c--)
  53                *--dst = *--src;
  54
  55        return v_dst;
  56}
  57#else /* CONFIG_OPT_LIB_FUNCTION */
  58void *memmove(void *v_dst, const void *v_src, __kernel_size_t c)
  59{
  60        const char *src = v_src;
  61        char *dst = v_dst;
  62        const uint32_t *i_src;
  63        uint32_t *i_dst;
  64
  65        if (!c)
  66                return v_dst;
  67
  68        /* Use memcpy when source is higher than dest */
  69        if (v_dst <= v_src)
  70                return memcpy(v_dst, v_src, c);
  71
  72        /* The following code tries to optimize the copy by using unsigned
  73         * alignment. This will work fine if both source and destination are
  74         * aligned on the same boundary. However, if they are aligned on
  75         * different boundaries shifts will be necessary. This might result in
  76         * bad performance on MicroBlaze systems without a barrel shifter.
  77         */
  78        /* FIXME this part needs more test */
  79        /* Do a descending copy - this is a bit trickier! */
  80        dst += c;
  81        src += c;
  82
  83        if (c >= 4) {
  84                unsigned  value, buf_hold;
  85
  86                /* Align the destination to a word boundary. */
  87                /* This is done in an endian independent manner. */
  88
  89                switch ((unsigned long)dst & 3) {
  90                case 3:
  91                        *--dst = *--src;
  92                        --c;
  93                        fallthrough;
  94                case 2:
  95                        *--dst = *--src;
  96                        --c;
  97                        fallthrough;
  98                case 1:
  99                        *--dst = *--src;
 100                        --c;
 101                }
 102
 103                i_dst = (void *)dst;
 104                /* Choose a copy scheme based on the source */
 105                /* alignment relative to dstination. */
 106                switch ((unsigned long)src & 3) {
 107                case 0x0:       /* Both byte offsets are aligned */
 108
 109                        i_src  = (const void *)src;
 110
 111                        for (; c >= 4; c -= 4)
 112                                *--i_dst = *--i_src;
 113
 114                        src  = (const void *)i_src;
 115                        break;
 116                case 0x1:       /* Unaligned - Off by 1 */
 117                        /* Word align the source */
 118                        i_src = (const void *) (((unsigned)src + 4) & ~3);
 119#ifndef __MICROBLAZEEL__
 120                        /* Load the holding buffer */
 121                        buf_hold = *--i_src >> 24;
 122
 123                        for (; c >= 4; c -= 4) {
 124                                value = *--i_src;
 125                                *--i_dst = buf_hold << 8 | value;
 126                                buf_hold = value >> 24;
 127                        }
 128#else
 129                        /* Load the holding buffer */
 130                        buf_hold = (*--i_src & 0xFF) << 24;
 131
 132                        for (; c >= 4; c -= 4) {
 133                                value = *--i_src;
 134                                *--i_dst = buf_hold |
 135                                                ((value & 0xFFFFFF00) >> 8);
 136                                buf_hold = (value  & 0xFF) << 24;
 137                        }
 138#endif
 139                        /* Realign the source */
 140                        src = (const void *)i_src;
 141                        src += 1;
 142                        break;
 143                case 0x2:       /* Unaligned - Off by 2 */
 144                        /* Word align the source */
 145                        i_src = (const void *) (((unsigned)src + 4) & ~3);
 146#ifndef __MICROBLAZEEL__
 147                        /* Load the holding buffer */
 148                        buf_hold = *--i_src >> 16;
 149
 150                        for (; c >= 4; c -= 4) {
 151                                value = *--i_src;
 152                                *--i_dst = buf_hold << 16 | value;
 153                                buf_hold = value >> 16;
 154                        }
 155#else
 156                        /* Load the holding buffer */
 157                        buf_hold = (*--i_src & 0xFFFF) << 16;
 158
 159                        for (; c >= 4; c -= 4) {
 160                                value = *--i_src;
 161                                *--i_dst = buf_hold |
 162                                                ((value & 0xFFFF0000) >> 16);
 163                                buf_hold = (value & 0xFFFF) << 16;
 164                        }
 165#endif
 166                        /* Realign the source */
 167                        src = (const void *)i_src;
 168                        src += 2;
 169                        break;
 170                case 0x3:       /* Unaligned - Off by 3 */
 171                        /* Word align the source */
 172                        i_src = (const void *) (((unsigned)src + 4) & ~3);
 173#ifndef __MICROBLAZEEL__
 174                        /* Load the holding buffer */
 175                        buf_hold = *--i_src >> 8;
 176
 177                        for (; c >= 4; c -= 4) {
 178                                value = *--i_src;
 179                                *--i_dst = buf_hold << 24 | value;
 180                                buf_hold = value >> 8;
 181                        }
 182#else
 183                        /* Load the holding buffer */
 184                        buf_hold = (*--i_src & 0xFFFFFF) << 8;
 185
 186                        for (; c >= 4; c -= 4) {
 187                                value = *--i_src;
 188                                *--i_dst = buf_hold |
 189                                                ((value & 0xFF000000) >> 24);
 190                                buf_hold = (value & 0xFFFFFF) << 8;
 191                        }
 192#endif
 193                        /* Realign the source */
 194                        src = (const void *)i_src;
 195                        src += 3;
 196                        break;
 197                }
 198                dst = (void *)i_dst;
 199        }
 200
 201        /* simple fast copy, ... unless a cache boundary is crossed */
 202        /* Finish off any remaining bytes */
 203        switch (c) {
 204        case 4:
 205                *--dst = *--src;
 206                fallthrough;
 207        case 3:
 208                *--dst = *--src;
 209                fallthrough;
 210        case 2:
 211                *--dst = *--src;
 212                fallthrough;
 213        case 1:
 214                *--dst = *--src;
 215        }
 216        return v_dst;
 217}
 218#endif /* CONFIG_OPT_LIB_FUNCTION */
 219EXPORT_SYMBOL(memmove);
 220#endif /* __HAVE_ARCH_MEMMOVE */
 221