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, unsuccesfully, 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 34 void *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 } 174 EXPORT_SYMBOL(memmove); 175 #endif /* __HAVE_ARCH_MEMMOVE */ 176