memmove.c 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216
  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. #include <linux/export.h>
  27. #include <linux/types.h>
  28. #include <linux/stddef.h>
  29. #include <linux/compiler.h>
  30. #include <linux/string.h>
  31. #ifdef __HAVE_ARCH_MEMMOVE
  32. #ifndef CONFIG_OPT_LIB_FUNCTION
  33. void *memmove(void *v_dst, const void *v_src, __kernel_size_t c)
  34. {
  35. const char *src = v_src;
  36. char *dst = v_dst;
  37. if (!c)
  38. return v_dst;
  39. /* Use memcpy when source is higher than dest */
  40. if (v_dst <= v_src)
  41. return memcpy(v_dst, v_src, c);
  42. /* copy backwards, from end to beginning */
  43. src += c;
  44. dst += c;
  45. /* Simple, byte oriented memmove. */
  46. while (c--)
  47. *--dst = *--src;
  48. return v_dst;
  49. }
  50. #else /* CONFIG_OPT_LIB_FUNCTION */
  51. void *memmove(void *v_dst, const void *v_src, __kernel_size_t c)
  52. {
  53. const char *src = v_src;
  54. char *dst = v_dst;
  55. const uint32_t *i_src;
  56. uint32_t *i_dst;
  57. if (!c)
  58. return v_dst;
  59. /* Use memcpy when source is higher than dest */
  60. if (v_dst <= v_src)
  61. return memcpy(v_dst, v_src, c);
  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. if (c >= 4) {
  73. unsigned value, buf_hold;
  74. /* Align the destination to a word boundary. */
  75. /* This is done in an endian independent manner. */
  76. switch ((unsigned long)dst & 3) {
  77. case 3:
  78. *--dst = *--src;
  79. --c;
  80. case 2:
  81. *--dst = *--src;
  82. --c;
  83. case 1:
  84. *--dst = *--src;
  85. --c;
  86. }
  87. i_dst = (void *)dst;
  88. /* Choose a copy scheme based on the source */
  89. /* alignment relative to dstination. */
  90. switch ((unsigned long)src & 3) {
  91. case 0x0: /* Both byte offsets are aligned */
  92. i_src = (const void *)src;
  93. for (; c >= 4; c -= 4)
  94. *--i_dst = *--i_src;
  95. src = (const void *)i_src;
  96. break;
  97. case 0x1: /* Unaligned - Off by 1 */
  98. /* Word align the source */
  99. i_src = (const void *) (((unsigned)src + 4) & ~3);
  100. #ifndef __MICROBLAZEEL__
  101. /* Load the holding buffer */
  102. buf_hold = *--i_src >> 24;
  103. for (; c >= 4; c -= 4) {
  104. value = *--i_src;
  105. *--i_dst = buf_hold << 8 | value;
  106. buf_hold = value >> 24;
  107. }
  108. #else
  109. /* Load the holding buffer */
  110. buf_hold = (*--i_src & 0xFF) << 24;
  111. for (; c >= 4; c -= 4) {
  112. value = *--i_src;
  113. *--i_dst = buf_hold |
  114. ((value & 0xFFFFFF00) >> 8);
  115. buf_hold = (value & 0xFF) << 24;
  116. }
  117. #endif
  118. /* Realign the source */
  119. src = (const void *)i_src;
  120. src += 1;
  121. break;
  122. case 0x2: /* Unaligned - Off by 2 */
  123. /* Word align the source */
  124. i_src = (const void *) (((unsigned)src + 4) & ~3);
  125. #ifndef __MICROBLAZEEL__
  126. /* Load the holding buffer */
  127. buf_hold = *--i_src >> 16;
  128. for (; c >= 4; c -= 4) {
  129. value = *--i_src;
  130. *--i_dst = buf_hold << 16 | value;
  131. buf_hold = value >> 16;
  132. }
  133. #else
  134. /* Load the holding buffer */
  135. buf_hold = (*--i_src & 0xFFFF) << 16;
  136. for (; c >= 4; c -= 4) {
  137. value = *--i_src;
  138. *--i_dst = buf_hold |
  139. ((value & 0xFFFF0000) >> 16);
  140. buf_hold = (value & 0xFFFF) << 16;
  141. }
  142. #endif
  143. /* Realign the source */
  144. src = (const void *)i_src;
  145. src += 2;
  146. break;
  147. case 0x3: /* Unaligned - Off by 3 */
  148. /* Word align the source */
  149. i_src = (const void *) (((unsigned)src + 4) & ~3);
  150. #ifndef __MICROBLAZEEL__
  151. /* Load the holding buffer */
  152. buf_hold = *--i_src >> 8;
  153. for (; c >= 4; c -= 4) {
  154. value = *--i_src;
  155. *--i_dst = buf_hold << 24 | value;
  156. buf_hold = value >> 8;
  157. }
  158. #else
  159. /* Load the holding buffer */
  160. buf_hold = (*--i_src & 0xFFFFFF) << 8;
  161. for (; c >= 4; c -= 4) {
  162. value = *--i_src;
  163. *--i_dst = buf_hold |
  164. ((value & 0xFF000000) >> 24);
  165. buf_hold = (value & 0xFFFFFF) << 8;
  166. }
  167. #endif
  168. /* Realign the source */
  169. src = (const void *)i_src;
  170. src += 3;
  171. break;
  172. }
  173. dst = (void *)i_dst;
  174. }
  175. /* simple fast copy, ... unless a cache boundary is crossed */
  176. /* Finish off any remaining bytes */
  177. switch (c) {
  178. case 4:
  179. *--dst = *--src;
  180. case 3:
  181. *--dst = *--src;
  182. case 2:
  183. *--dst = *--src;
  184. case 1:
  185. *--dst = *--src;
  186. }
  187. return v_dst;
  188. }
  189. #endif /* CONFIG_OPT_LIB_FUNCTION */
  190. EXPORT_SYMBOL(memmove);
  191. #endif /* __HAVE_ARCH_MEMMOVE */