1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* |
3 | * This provides an optimized implementation of memcpy, and a simplified |
4 | * implementation of memset and memmove. These are used here because the |
5 | * standard kernel runtime versions are not yet available and we don't |
6 | * trust the gcc built-in implementations as they may do unexpected things |
7 | * (e.g. FPU ops) in the minimal decompression stub execution environment. |
8 | */ |
9 | #include "error.h" |
10 | |
11 | #include "../string.c" |
12 | |
13 | #ifdef CONFIG_X86_32 |
14 | static void *____memcpy(void *dest, const void *src, size_t n) |
15 | { |
16 | int d0, d1, d2; |
17 | asm volatile( |
18 | "rep ; movsl\n\t" |
19 | "movl %4,%%ecx\n\t" |
20 | "rep ; movsb\n\t" |
21 | : "=&c" (d0), "=&D" (d1), "=&S" (d2) |
22 | : "0" (n >> 2), "g" (n & 3), "1" (dest), "2" (src) |
23 | : "memory" ); |
24 | |
25 | return dest; |
26 | } |
27 | #else |
28 | static void *____memcpy(void *dest, const void *src, size_t n) |
29 | { |
30 | long d0, d1, d2; |
31 | asm volatile( |
32 | "rep ; movsq\n\t" |
33 | "movq %4,%%rcx\n\t" |
34 | "rep ; movsb\n\t" |
35 | : "=&c" (d0), "=&D" (d1), "=&S" (d2) |
36 | : "0" (n >> 3), "g" (n & 7), "1" (dest), "2" (src) |
37 | : "memory" ); |
38 | |
39 | return dest; |
40 | } |
41 | #endif |
42 | |
43 | void *memset(void *s, int c, size_t n) |
44 | { |
45 | int i; |
46 | char *ss = s; |
47 | |
48 | for (i = 0; i < n; i++) |
49 | ss[i] = c; |
50 | return s; |
51 | } |
52 | |
53 | void *memmove(void *dest, const void *src, size_t n) |
54 | { |
55 | unsigned char *d = dest; |
56 | const unsigned char *s = src; |
57 | |
58 | if (d <= s || d - s >= n) |
59 | return ____memcpy(dest, src, n); |
60 | |
61 | while (n-- > 0) |
62 | d[n] = s[n]; |
63 | |
64 | return dest; |
65 | } |
66 | |
67 | /* Detect and warn about potential overlaps, but handle them with memmove. */ |
68 | void *memcpy(void *dest, const void *src, size_t n) |
69 | { |
70 | if (dest > src && dest - src < n) { |
71 | warn(m: "Avoiding potentially unsafe overlapping memcpy()!" ); |
72 | return memmove(dest, src, n); |
73 | } |
74 | return ____memcpy(dest, src, n); |
75 | } |
76 | |
77 | #ifdef CONFIG_KASAN |
78 | extern void *__memset(void *s, int c, size_t n) __alias(memset); |
79 | extern void *__memmove(void *dest, const void *src, size_t n) __alias(memmove); |
80 | extern void *__memcpy(void *dest, const void *src, size_t n) __alias(memcpy); |
81 | #endif |
82 | |