memcpy.c 4.9 KB

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