The Pedigree Project  0.1
memory.c
1 /*
2  * Copyright (c) 2008-2014, Pedigree Developers
3  *
4  * Please see the CONTRIB file in the root of the source tree for a full
5  * list of contributors.
6  *
7  * Permission to use, copy, modify, and distribute this software for any
8  * purpose with or without fee is hereby granted, provided that the above
9  * copyright notice and this permission notice appear in all copies.
10  *
11  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18  */
19 
20 #include "pedigree/kernel/compiler.h"
21 #include "pedigree/kernel/processor/types.h"
22 #include "pedigree/kernel/utilities/assert.h"
23 #include "pedigree/kernel/utilities/utility.h"
24 
25 #undef memcpy
26 
27 #define WITH_SSE 0
28 #define SSE_THRESHOLD 1024
29 #define STOSB_THRESHOLD 64
30 
31 #ifdef HOSTED_X64
32 #define X64
33 #endif
34 
35 #ifdef UTILITY_LINUX_COVERAGE
36 #undef _STRING_H
37 #include <string.h>
38 #else
39 
40 #ifdef UTILITY_LINUX
41 #define EXPORT static
42 #else
43 #define EXPORT EXPORTED_PUBLIC
44 #endif
45 
46 extern void memzero_xmm_aligned(void *, size_t);
47 extern void memzero_xmm(void *, size_t);
48 
49 EXPORT int memcmp(const void *p1, const void *p2, size_t len) PURE;
50 EXPORT void *memset(void *buf, int c, size_t n);
51 void *WordSet(void *buf, int c, size_t n);
52 void *DoubleWordSet(void *buf, unsigned int c, size_t n);
53 void *QuadWordSet(void *buf, unsigned long long c, size_t n);
54 
55 EXPORT void *memcpy(void *restrict s1, const void *restrict s2, size_t n);
56 EXPORT void *memmove(void *s1, const void *s2, size_t n);
57 
58 // asan provides a memcpy/memset/etc that we care about more than our custom
59 // ones, in general.
60 #if !HAS_ADDRESS_SANITIZER
61 
62 EXPORT int memcmp(const void *p1, const void *p2, size_t len)
63 {
64  const char *a = (const char *) p1;
65  const char *b = (const char *) p2;
66  size_t i = 0;
67  int r = 0;
68  for (; i < len; i++)
69  {
70  if ((r = a[i] - b[i]) != 0)
71  break;
72  }
73  return r;
74 }
75 
76 EXPORT void *memset(void *buf, int c, size_t n)
77 {
78 #ifdef TARGET_IS_X86
79  if (n >= STOSB_THRESHOLD)
80  {
81  int a, b;
82  __asm__ __volatile__("rep stosb"
83  : "=&D"(a), "=&c"(b)
84  : "0"(buf), "a"(c), "1"(n)
85  : "memory");
86  return buf;
87  }
88 #endif
89  unsigned char *tmp = (unsigned char *) buf;
90  while (n--)
91  {
92  *tmp++ = c;
93  }
94  return buf;
95 }
96 
97 EXPORT void *memcpy(void *restrict s1, const void *restrict s2, size_t n)
98 {
99 #ifdef TARGET_IS_X86
100  if (n >= STOSB_THRESHOLD)
101  {
102  int a, b, c;
103  __asm__ __volatile__("rep movsb"
104  : "=&c"(a), "=&D"(b), "=&S"(c)
105  : "1"(s1), "2"(s2), "0"(n)
106  : "memory");
107  return s1;
108  }
109 #endif
110  const unsigned char *restrict sp = (const unsigned char *restrict) s2;
111  unsigned char *restrict dp = (unsigned char *restrict) s1;
112  while (n--)
113  *dp++ = *sp++;
114  return s1;
115 }
116 
117 #ifdef TARGET_IS_X86
118 static inline void *memmove_x86(void *s1, const void *s2, size_t n)
119 {
120  // Perform rep movsb in reverse.
121  const unsigned char *sp = (const unsigned char *) s2 + (n - 1);
122  unsigned char *dp = (unsigned char *) s1 + (n - 1);
123 
124  int a, b, c;
125  __asm__ __volatile__("std; rep movsb; cld"
126  : "=&c"(a), "=&D"(b), "=&S"(c)
127  : "1"(dp), "2"(sp), "0"(n)
128  : "memory");
129  return s1;
130 }
131 #endif
132 
133 EXPORT void *memmove(void *s1, const void *s2, size_t n)
134 {
135  if (UNLIKELY(!n))
136  return s1;
137 
138  const size_t orig_n = n;
139  if (LIKELY((s1 < s2) || !overlaps(s1, s2, n)))
140  {
141  // No overlap, or there's overlap but we can copy forwards.
142  memcpy(s1, s2, n);
143  }
144  else
145  {
146 #ifdef TARGET_IS_X86
147  if (n >= STOSB_THRESHOLD)
148  {
149  memmove_x86(s1, s2, n);
150  }
151  else
152  {
153 #endif
154  // Writing bytes from s2 into s1 cannot be done forwards, use memmove.
155  const unsigned char *sp = (const unsigned char *) s2 + (n - 1);
156  unsigned char *dp = (unsigned char *) s1 + (n - 1);
157  for (; n != 0; n--)
158  *dp-- = *sp--;
159 #ifdef TARGET_IS_X86
160  }
161 #endif
162  }
163 
164 #ifdef EXCESSIVE_ADDITIONAL_CHECKS
165  // We can't memcmp if the regions overlap at all.
166  if (LIKELY(!overlaps(s1, s2, orig_n)))
167  {
168  assert(!memcmp(s1, s2, orig_n));
169  }
170 #endif
171 
172  return s1;
173 }
174 
175 #endif // HAS_ADDRESS_SANITIZER
176 
177 #endif // UTILITY_LINUX_COVERAGE
178 
179 int overlaps(const void *s1, const void *s2, size_t n)
180 {
181  uintptr_t a = (uintptr_t) s1;
182  uintptr_t a_end = (uintptr_t) s1 + n;
183  uintptr_t b = (uintptr_t) s2;
184  uintptr_t b_end = (uintptr_t) s2 + n;
185 
186  return (a <= b_end) && (b <= a_end) ? 1 : 0;
187 }
188 
189 void *WordSet(void *buf, int c, size_t n)
190 {
191 #ifdef TARGET_IS_X86
192  if (n >= STOSB_THRESHOLD)
193  {
194  int a, b;
195  __asm__ __volatile__("rep stosw"
196  : "=&D"(a), "=&c"(b)
197  : "0"(buf), "a"(c), "1"(n)
198  : "memory");
199  return buf;
200  }
201 #endif
202  unsigned short *tmp = (unsigned short *) buf;
203  while (n--)
204  {
205  *tmp++ = c;
206  }
207  return buf;
208 }
209 
210 void *DoubleWordSet(void *buf, unsigned int c, size_t n)
211 {
212 #ifdef TARGET_IS_X86
213  if (n >= STOSB_THRESHOLD)
214  {
215  int a, b;
216  __asm__ __volatile__("rep stosl"
217  : "=&D"(a), "=&c"(b)
218  : "0"(buf), "a"(c), "1"(n)
219  : "memory");
220  return buf;
221  }
222 #endif
223  unsigned int *tmp = (unsigned int *) buf;
224  while (n--)
225  {
226  *tmp++ = c;
227  }
228  return buf;
229 }
230 
231 void *QuadWordSet(void *buf, unsigned long long c, size_t n)
232 {
233 #ifdef TARGET_IS_X86
234  if (n >= STOSB_THRESHOLD)
235  {
236  int a, b;
237  __asm__ __volatile__("rep stosq"
238  : "=&D"(a), "=&c"(b)
239  : "0"(buf), "a"(c), "1"(n)
240  : "memory");
241  return buf;
242  }
243 #endif
244  unsigned long long *p = (unsigned long long *) buf;
245  while (n--)
246  *p++ = c;
247  return buf;
248 }
249 
250 // We still need memcpy etc as linked symbols for GCC optimisations, but we
251 // don't have to have their prototypes widely available. So, we implement our
252 // main functions in terms of the base calls.
253 void *ForwardMemoryCopy(void *a, const void *b, size_t c)
254 {
255  return memcpy(a, b, c);
256 }
257 
258 void *MemoryCopy(void *a, const void *b, size_t c)
259 {
260  return memmove(a, b, c);
261 }
262 
263 void *ByteSet(void *a, int b, size_t c)
264 {
265  return memset(a, b, c);
266 }
267 
268 int MemoryCompare(const void *a, const void *b, size_t c)
269 {
270  return memcmp(a, b, c);
271 }
#define assert(x)
Definition: assert.h:37