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 memcpy. 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 32 #include <linux/string.h> 33 34 #ifdef CONFIG_OPT_LIB_FUNCTION 35 void *memcpy(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 /* The following code tries to optimize the copy by using unsigned 41 * alignment. This will work fine if both source and destination are 42 * aligned on the same boundary. However, if they are aligned on 43 * different boundaries shifts will be necessary. This might result in 44 * bad performance on MicroBlaze systems without a barrel shifter. 45 */ 46 const uint32_t *i_src; 47 uint32_t *i_dst; 48 49 if (likely(c >= 4)) { 50 unsigned value, buf_hold; 51 52 /* Align the destination to a word boundary. */ 53 /* This is done in an endian independent manner. */ 54 switch ((unsigned long)dst & 3) { 55 case 1: 56 *dst++ = *src++; 57 --c; 58 fallthrough; 59 case 2: 60 *dst++ = *src++; 61 --c; 62 fallthrough; 63 case 3: 64 *dst++ = *src++; 65 --c; 66 } 67 68 i_dst = (void *)dst; 69 70 /* Choose a copy scheme based on the source */ 71 /* alignment relative to destination. */ 72 switch ((unsigned long)src & 3) { 73 case 0x0: /* Both byte offsets are aligned */ 74 i_src = (const void *)src; 75 76 for (; c >= 4; c -= 4) 77 *i_dst++ = *i_src++; 78 79 src = (const void *)i_src; 80 break; 81 case 0x1: /* Unaligned - Off by 1 */ 82 /* Word align the source */ 83 i_src = (const void *) ((unsigned)src & ~3); 84 #ifndef __MICROBLAZEEL__ 85 /* Load the holding buffer */ 86 buf_hold = *i_src++ << 8; 87 88 for (; c >= 4; c -= 4) { 89 value = *i_src++; 90 *i_dst++ = buf_hold | value >> 24; 91 buf_hold = value << 8; 92 } 93 #else 94 /* Load the holding buffer */ 95 buf_hold = (*i_src++ & 0xFFFFFF00) >> 8; 96 97 for (; c >= 4; c -= 4) { 98 value = *i_src++; 99 *i_dst++ = buf_hold | ((value & 0xFF) << 24); 100 buf_hold = (value & 0xFFFFFF00) >> 8; 101 } 102 #endif 103 /* Realign the source */ 104 src = (const void *)i_src; 105 src -= 3; 106 break; 107 case 0x2: /* Unaligned - Off by 2 */ 108 /* Word align the source */ 109 i_src = (const void *) ((unsigned)src & ~3); 110 #ifndef __MICROBLAZEEL__ 111 /* Load the holding buffer */ 112 buf_hold = *i_src++ << 16; 113 114 for (; c >= 4; c -= 4) { 115 value = *i_src++; 116 *i_dst++ = buf_hold | value >> 16; 117 buf_hold = value << 16; 118 } 119 #else 120 /* Load the holding buffer */ 121 buf_hold = (*i_src++ & 0xFFFF0000) >> 16; 122 123 for (; c >= 4; c -= 4) { 124 value = *i_src++; 125 *i_dst++ = buf_hold | ((value & 0xFFFF) << 16); 126 buf_hold = (value & 0xFFFF0000) >> 16; 127 } 128 #endif 129 /* Realign the source */ 130 src = (const void *)i_src; 131 src -= 2; 132 break; 133 case 0x3: /* Unaligned - Off by 3 */ 134 /* Word align the source */ 135 i_src = (const void *) ((unsigned)src & ~3); 136 #ifndef __MICROBLAZEEL__ 137 /* Load the holding buffer */ 138 buf_hold = *i_src++ << 24; 139 140 for (; c >= 4; c -= 4) { 141 value = *i_src++; 142 *i_dst++ = buf_hold | value >> 8; 143 buf_hold = value << 24; 144 } 145 #else 146 /* Load the holding buffer */ 147 buf_hold = (*i_src++ & 0xFF000000) >> 24; 148 149 for (; c >= 4; c -= 4) { 150 value = *i_src++; 151 *i_dst++ = buf_hold | ((value & 0xFFFFFF) << 8); 152 buf_hold = (value & 0xFF000000) >> 24; 153 } 154 #endif 155 /* Realign the source */ 156 src = (const void *)i_src; 157 src -= 1; 158 break; 159 } 160 dst = (void *)i_dst; 161 } 162 163 /* Finish off any remaining bytes */ 164 /* simple fast copy, ... unless a cache boundary is crossed */ 165 switch (c) { 166 case 3: 167 *dst++ = *src++; 168 fallthrough; 169 case 2: 170 *dst++ = *src++; 171 fallthrough; 172 case 1: 173 *dst++ = *src++; 174 } 175 176 return v_dst; 177 } 178 EXPORT_SYMBOL(memcpy); 179 #endif /* CONFIG_OPT_LIB_FUNCTION */ 180