source: mainline/common/stdc/mem.c@ ef4d684

topic/simplify-dev-export
Last change on this file since ef4d684 was b169619, checked in by Jiří Zárevúcky <zarevucky.jiri@…>, 20 months ago

Deduplicate mem functions

There are a number of functions which are copied between
kernel, libc, and potentially boot too. mem*() functions
are first such offenders. All this duplicate code will
be moved to directory 'common'.

  • Property mode set to 100644
File size: 6.3 KB
Line 
1/*
2 * Copyright (c) 2005 Martin Decky
3 * Copyright (c) 2018 Jiri Svoboda
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * - Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * - Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * - The name of the author may not be used to endorse or promote products
16 * derived from this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29
30/** @addtogroup libc
31 * @{
32 */
33/** @file
34 */
35
36#include "../include/mem.h"
37
38#include <stdlib.h>
39#include <stddef.h>
40#include <stdint.h>
41#include "cc.h"
42
43#undef memset
44#undef memcpy
45#undef memcmp
46#undef memmove
47#undef memchr
48
49/** Fill memory block with a constant value. */
50DO_NOT_DISCARD
51ATTRIBUTE_OPTIMIZE_NO_TLDP
52 void *memset(void *dest, int b, size_t n)
53{
54 char *pb;
55 unsigned long *pw;
56 size_t word_size;
57 size_t n_words;
58
59 unsigned long pattern;
60 size_t i;
61 size_t fill;
62
63 /* Fill initial segment. */
64 word_size = sizeof(unsigned long);
65 fill = word_size - ((uintptr_t) dest & (word_size - 1));
66 if (fill > n)
67 fill = n;
68
69 pb = dest;
70
71 i = fill;
72 while (i-- != 0)
73 *pb++ = b;
74
75 /* Compute remaining size. */
76 n -= fill;
77 if (n == 0)
78 return dest;
79
80 n_words = n / word_size;
81 n = n % word_size;
82 pw = (unsigned long *) pb;
83
84 /* Create word-sized pattern for aligned segment. */
85 pattern = 0;
86 i = word_size;
87 while (i-- != 0)
88 pattern = (pattern << 8) | (uint8_t) b;
89
90 /* Fill aligned segment. */
91 i = n_words;
92 while (i-- != 0)
93 *pw++ = pattern;
94
95 pb = (char *) pw;
96
97 /* Fill final segment. */
98 i = n;
99 while (i-- != 0)
100 *pb++ = b;
101
102 return dest;
103}
104
105struct along {
106 unsigned long n;
107} __attribute__((packed));
108
109ATTRIBUTE_OPTIMIZE_NO_TLDP
110 static void *unaligned_memcpy(void *dst, const void *src, size_t n)
111{
112 size_t i, j;
113 struct along *adst = dst;
114 const struct along *asrc = src;
115
116 for (i = 0; i < n / sizeof(unsigned long); i++)
117 adst[i].n = asrc[i].n;
118
119 for (j = 0; j < n % sizeof(unsigned long); j++)
120 ((unsigned char *) (((unsigned long *) dst) + i))[j] =
121 ((unsigned char *) (((unsigned long *) src) + i))[j];
122
123 return (char *) dst;
124}
125
126/** Copy memory block. */
127DO_NOT_DISCARD
128ATTRIBUTE_OPTIMIZE_NO_TLDP
129 void *memcpy(void *dst, const void *src, size_t n)
130{
131 size_t i;
132 size_t mod, fill;
133 size_t word_size;
134 size_t n_words;
135
136 const unsigned long *srcw;
137 unsigned long *dstw;
138 const uint8_t *srcb;
139 uint8_t *dstb;
140
141 word_size = sizeof(unsigned long);
142
143 /*
144 * Are source and destination addresses congruent modulo word_size?
145 * If not, use unaligned_memcpy().
146 */
147
148 if (((uintptr_t) dst & (word_size - 1)) !=
149 ((uintptr_t) src & (word_size - 1)))
150 return unaligned_memcpy(dst, src, n);
151
152 /*
153 * mod is the address modulo word size. fill is the length of the
154 * initial buffer segment before the first word boundary.
155 * If the buffer is very short, use unaligned_memcpy(), too.
156 */
157
158 mod = (uintptr_t) dst & (word_size - 1);
159 fill = word_size - mod;
160 if (fill > n)
161 fill = n;
162
163 /* Copy the initial segment. */
164
165 srcb = src;
166 dstb = dst;
167
168 i = fill;
169 while (i-- != 0)
170 *dstb++ = *srcb++;
171
172 /* Compute remaining length. */
173
174 n -= fill;
175 if (n == 0)
176 return dst;
177
178 /* Pointers to aligned segment. */
179
180 dstw = (unsigned long *) dstb;
181 srcw = (const unsigned long *) srcb;
182
183 n_words = n / word_size; /* Number of whole words to copy. */
184 n -= n_words * word_size; /* Remaining bytes at the end. */
185
186 /* "Fast" copy. */
187 i = n_words;
188 while (i-- != 0)
189 *dstw++ = *srcw++;
190
191 /*
192 * Copy the rest.
193 */
194
195 srcb = (const uint8_t *) srcw;
196 dstb = (uint8_t *) dstw;
197
198 i = n;
199 while (i-- != 0)
200 *dstb++ = *srcb++;
201
202 return dst;
203}
204
205/** Move memory block with possible overlapping. */
206DO_NOT_DISCARD
207ATTRIBUTE_OPTIMIZE_NO_TLDP
208void *memmove(void *dst, const void *src, size_t n)
209{
210 const uint8_t *sp;
211 uint8_t *dp;
212
213 /* Nothing to do? */
214 if (src == dst)
215 return dst;
216
217 /* Non-overlapping? */
218 if (dst >= src + n || src >= dst + n) {
219 return memcpy(dst, src, n);
220 }
221
222 /* Which direction? */
223 if (src > dst) {
224 /* Forwards. */
225 sp = src;
226 dp = dst;
227
228 while (n-- != 0)
229 *dp++ = *sp++;
230 } else {
231 /* Backwards. */
232 sp = src + (n - 1);
233 dp = dst + (n - 1);
234
235 while (n-- != 0)
236 *dp-- = *sp--;
237 }
238
239 return dst;
240}
241
242/** Compare two memory areas.
243 *
244 * @param s1 Pointer to the first area to compare.
245 * @param s2 Pointer to the second area to compare.
246 * @param len Size of the areas in bytes.
247 *
248 * @return Zero if areas have the same contents. If they differ,
249 * the sign of the result is the same as the sign of the
250 * difference of the first pair of different bytes.
251 *
252 */
253DO_NOT_DISCARD
254ATTRIBUTE_OPTIMIZE_NO_TLDP
255 int memcmp(const void *s1, const void *s2, size_t len)
256{
257 uint8_t *u1 = (uint8_t *) s1;
258 uint8_t *u2 = (uint8_t *) s2;
259 size_t i;
260
261 for (i = 0; i < len; i++) {
262 if (*u1 != *u2)
263 return (int)(*u1) - (int)(*u2);
264 ++u1;
265 ++u2;
266 }
267
268 return 0;
269}
270
271/** Search memory area.
272 *
273 * @param s Memory area
274 * @param c Character (byte) to search for
275 * @param n Size of memory area in bytes
276 *
277 * @return Pointer to the first occurrence of @a c in the first @a n
278 * bytes of @a s or @c NULL if not found.
279 */
280DO_NOT_DISCARD
281ATTRIBUTE_OPTIMIZE_NO_TLDP
282void *memchr(const void *s, int c, size_t n)
283{
284 uint8_t *u = (uint8_t *) s;
285 unsigned char uc = (unsigned char) c;
286 size_t i;
287
288 for (i = 0; i < n; i++) {
289 if (u[i] == uc)
290 return (void *) &u[i];
291 }
292
293 return NULL;
294}
295
296/** @}
297 */
Note: See TracBrowser for help on using the repository browser.