string.c 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /*
  3. * arch/riscv/lib/string.c
  4. *
  5. * Copyright (C) 2021 Matteo Croce
  6. *
  7. * string functions optimized for 64 bit hardware which doesn't
  8. * handle unaligned memory accesses efficiently.
  9. *
  10. * May be freely distributed as part of Linux.
  11. */
  12. #include <stddef.h>
  13. #include <linux/types.h>
  14. #include <linux/module.h>
  15. #define BITS_PER_LONG 64
  16. typedef unsigned long uintptr_t;
  17. typedef __u64 u64;
  18. typedef __s64 s64;
  19. typedef __u32 u32;
  20. typedef __s32 s32;
  21. typedef __u16 u16;
  22. typedef __s16 s16;
  23. typedef __u8 u8;
  24. typedef __s8 s8;
  25. union types {
  26. u8 *u8;
  27. u16 *u16;
  28. u32 *u32;
  29. u64 *u64;
  30. unsigned long *ulong;
  31. uintptr_t ptr;
  32. };
  33. union ctypes {
  34. const u8 *u8;
  35. const u16 *u16;
  36. const u32 *u32;
  37. const u64 *u64;
  38. unsigned long *ulong;
  39. uintptr_t ptr;
  40. };
  41. /**
  42. * memcpy - Copy one area of memory to another
  43. * @dest: Where to copy to
  44. * @src: Where to copy from
  45. * @count: The size of the area.
  46. *
  47. * You should not use this function to access IO space, use memcpy_toio()
  48. * or memcpy_fromio() instead.
  49. */
  50. void *memcpy(void *dest, const void *src, size_t count)
  51. {
  52. static const void *labels[] = {
  53. &&u64, &&u8, &&u16, &&u8,
  54. &&u32, &&u8, &&u16, &&u8,
  55. };
  56. union types d = { .u8 = dest };
  57. union ctypes s = { .u8 = src };
  58. #ifdef HAVE_EFFICIENT_UNALIGNED_ACCESS
  59. int distance = 0;
  60. #else
  61. const int mask = BITS_PER_LONG / 8 - 1;
  62. int distance = (src - dest) & 7;
  63. for (; count && d.ptr & s.ptr & mask; count--)
  64. *d.u8++ = *s.u8++;
  65. #endif
  66. goto *labels[distance];
  67. u64:
  68. #if BITS_PER_LONG == 64
  69. for (; count >= 8; count -= 8)
  70. *d.u64++ = *s.u64++;
  71. #endif
  72. u32:
  73. for (; count >= 4; count -= 4)
  74. *d.u32++ = *s.u32++;
  75. u16:
  76. for (; count >= 2; count -= 2)
  77. *d.u16++ = *s.u16++;
  78. u8:
  79. while (count--)
  80. *d.u8++ = *s.u8++;
  81. return dest;
  82. }
  83. EXPORT_SYMBOL(memcpy);
  84. void *__memcpy(void *dest, const void *src, size_t count)
  85. {
  86. return memcpy(dest, src, count);
  87. }
  88. EXPORT_SYMBOL(__memcpy);
  89. /**
  90. * memmove - Copy one area of memory to another
  91. * @dest: Where to copy to
  92. * @src: Where to copy from
  93. * @count: The size of the area.
  94. *
  95. * Unlike memcpy(), memmove() copes with overlapping areas.
  96. */
  97. void *memmove(void *dest, const void *src, size_t count)
  98. {
  99. if (dest < src || src + count <= dest)
  100. return memcpy(dest, src, count);
  101. if (dest > src) {
  102. const char *s = src + count;
  103. char *tmp = dest + count;
  104. while (count--)
  105. *--tmp = *--s;
  106. }
  107. return dest;
  108. }
  109. EXPORT_SYMBOL(memmove);
  110. void *__memmove(void *dest, const void *src, size_t count)
  111. {
  112. return memmove(dest, src, count);
  113. }
  114. EXPORT_SYMBOL(__memmove);
  115. /**
  116. * memset - Fill a region of memory with the given value
  117. * @s: Pointer to the start of the area.
  118. * @c: The byte to fill the area with
  119. * @count: The size of the area.
  120. *
  121. * Do not use memset() to access IO space, use memset_io() instead.
  122. */
  123. void *memset(void *s, int c, size_t count)
  124. {
  125. const int bytes_long = BITS_PER_LONG / 8;
  126. u8 cc[] = { [0 ... bytes_long-1] = c };
  127. union ctypes src = { .u8 = cc };
  128. union types dest = { .u8 = s };
  129. #ifndef HAVE_EFFICIENT_UNALIGNED_ACCESS
  130. for (; count && dest.ptr % bytes_long; count--)
  131. *dest.u8++ = c;
  132. #endif
  133. for (; count >= bytes_long; count -= bytes_long)
  134. *dest.ulong++ = *src.ulong;
  135. while (count--)
  136. *dest.u8++ = c;
  137. return s;
  138. }
  139. EXPORT_SYMBOL(memset);
  140. void *__memset(void *s, int c, size_t count)
  141. {
  142. return memset(s, c, count);
  143. }
  144. EXPORT_SYMBOL(__memset);