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/types.h>
  28#include <linux/stddef.h>
  29#include <linux/compiler.h>
  30#include <linux/module.h>
  31#include <linux/string.h>
  32
  33#ifdef __HAVE_ARCH_MEMMOVE
  34void *memmove(void *v_dst, const void *v_src, __kernel_size_t c)
  35{
  36        const char *src = v_src;
  37        char *dst = v_dst;
  38
  39#ifdef CONFIG_OPT_LIB_FUNCTION
  40        const uint32_t *i_src;
  41        uint32_t *i_dst;
  42#endif
  43
  44        if (!c)
  45                return v_dst;
  46
  47        /* Use memcpy when source is higher than dest */
  48        if (v_dst <= v_src)
  49                return memcpy(v_dst, v_src, c);
  50
  51#ifndef CONFIG_OPT_LIB_FUNCTION
  52        /* copy backwards, from end to beginning */
  53        src += c;
  54        dst += c;
  55
  56        /* Simple, byte oriented memmove. */
  57        while (c--)
  58                *--dst = *--src;
  59
  60        return v_dst;
  61#else
  62        /* The following code tries to optimize the copy by using unsigned
  63         * alignment. This will work fine if both source and destination are
  64         * aligned on the same boundary. However, if they are aligned on
  65         * different boundaries shifts will be necessary. This might result in
  66         * bad performance on MicroBlaze systems without a barrel shifter.
  67         */
  68        /* FIXME this part needs more test */
  69        /* Do a descending copy - this is a bit trickier! */
  70        dst += c;
  71        src += c;
  72
  73        if (c >= 4) {
  74                unsigned  value, buf_hold;
  75
  76                /* Align the destination to a word boundry. */
  77                /* This is done in an endian independant manner. */
  78
  79                switch ((unsigned long)dst & 3) {
  80                case 3:
  81                        *--dst = *--src;
  82                        --c;
  83                case 2:
  84                        *--dst = *--src;
  85                        --c;
  86                case 1:
  87                        *--dst = *--src;
  88                        --c;
  89                }
  90
  91                i_dst = (void *)dst;
  92                /* Choose a copy scheme based on the source */
  93                /* alignment relative to dstination. */
  94                switch ((unsigned long)src & 3) {
  95                case 0x0:       /* Both byte offsets are aligned */
  96
  97                        i_src  = (const void *)src;
  98
  99                        for (; c >= 4; c -= 4)
 100                                *--i_dst = *--i_src;
 101
 102                        src  = (const void *)i_src;
 103                        break;
 104                case 0x1:       /* Unaligned - Off by 1 */
 105                        /* Word align the source */
 106                        i_src = (const void *) (((unsigned)src + 4) & ~3);
 107
 108                        /* Load the holding buffer */
 109                        buf_hold = *--i_src >> 24;
 110
 111                        for (; c >= 4; c -= 4) {
 112                                value = *--i_src;
 113                                *--i_dst = buf_hold << 8 | value;
 114                                buf_hold = value >> 24;
 115                        }
 116
 117                        /* Realign the source */
 118                        src = (const void *)i_src;
 119                        src += 1;
 120                        break;
 121                case 0x2:       /* Unaligned - Off by 2 */
 122                        /* Word align the source */
 123                        i_src = (const void *) (((unsigned)src + 4) & ~3);
 124
 125                        /* Load the holding buffer */
 126                        buf_hold = *--i_src >> 16;
 127
 128                        for (; c >= 4; c -= 4) {
 129                                value = *--i_src;
 130                                *--i_dst = buf_hold << 16 | value;
 131                                buf_hold = value >> 16;
 132                        }
 133
 134                        /* Realign the source */
 135                        src = (const void *)i_src;
 136                        src += 2;
 137                        break;
 138                case 0x3:       /* Unaligned - Off by 3 */
 139                        /* Word align the source */
 140                        i_src = (const void *) (((unsigned)src + 4) & ~3);
 141
 142                        /* Load the holding buffer */
 143                        buf_hold = *--i_src >> 8;
 144
 145                        for (; c >= 4; c -= 4) {
 146                                value = *--i_src;
 147                                *--i_dst = buf_hold << 24 | value;
 148                                buf_hold = value >> 8;
 149                        }
 150
 151                        /* Realign the source */
 152                        src = (const void *)i_src;
 153                        src += 3;
 154                        break;
 155                }
 156                dst = (void *)i_dst;
 157        }
 158
 159        /* simple fast copy, ... unless a cache boundry is crossed */
 160        /* Finish off any remaining bytes */
 161        switch (c) {
 162        case 4:
 163                *--dst = *--src;
 164        case 3:
 165                *--dst = *--src;
 166        case 2:
 167                *--dst = *--src;
 168        case 1:
 169                *--dst = *--src;
 170        }
 171        return v_dst;
 172#endif
 173}
 174EXPORT_SYMBOL(memmove);
 175#endif /* __HAVE_ARCH_MEMMOVE */
 176
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.