1 #include <linux/string.h>
2 #include <linux/module.h>
4 #include <linux/kmsan-checks.h>
6 #define movs(type,to,from) \
7 asm volatile("movs" type:"=&D" (to), "=&S" (from):"0" (to), "1" (from):"memory")
9 /* Originally from i386/string.h */
10 static __always_inline
void rep_movs(void *to
, const void *from
, size_t n
)
12 unsigned long d0
, d1
, d2
;
13 asm volatile("rep ; movsl\n\t"
17 "1:\ttestb $1,%b4\n\t"
21 : "=&c" (d0
), "=&D" (d1
), "=&S" (d2
)
22 : "0" (n
/ 4), "q" (n
), "1" ((long)to
), "2" ((long)from
)
26 static void string_memcpy_fromio(void *to
, const volatile void __iomem
*from
, size_t n
)
28 const void *orig_to
= to
;
29 const size_t orig_n
= n
;
34 /* Align any unaligned source IO */
35 if (unlikely(1 & (unsigned long)from
)) {
39 if (n
> 1 && unlikely(2 & (unsigned long)from
)) {
43 rep_movs(to
, (const void *)from
, n
);
44 /* KMSAN must treat values read from devices as initialized. */
45 kmsan_unpoison_memory(orig_to
, orig_n
);
48 static void string_memcpy_toio(volatile void __iomem
*to
, const void *from
, size_t n
)
53 /* Make sure uninitialized memory isn't copied to devices. */
54 kmsan_check_memory(from
, n
);
55 /* Align any unaligned destination IO */
56 if (unlikely(1 & (unsigned long)to
)) {
60 if (n
> 1 && unlikely(2 & (unsigned long)to
)) {
64 rep_movs((void *)to
, (const void *) from
, n
);
67 static void unrolled_memcpy_fromio(void *to
, const volatile void __iomem
*from
, size_t n
)
69 const volatile char __iomem
*in
= from
;
73 for (i
= 0; i
< n
; ++i
)
74 out
[i
] = readb(&in
[i
]);
77 static void unrolled_memcpy_toio(volatile void __iomem
*to
, const void *from
, size_t n
)
79 volatile char __iomem
*out
= to
;
80 const char *in
= from
;
83 for (i
= 0; i
< n
; ++i
)
84 writeb(in
[i
], &out
[i
]);
87 static void unrolled_memset_io(volatile void __iomem
*a
, int b
, size_t c
)
89 volatile char __iomem
*mem
= a
;
92 for (i
= 0; i
< c
; ++i
)
96 void memcpy_fromio(void *to
, const volatile void __iomem
*from
, size_t n
)
98 if (cc_platform_has(CC_ATTR_GUEST_UNROLL_STRING_IO
))
99 unrolled_memcpy_fromio(to
, from
, n
);
101 string_memcpy_fromio(to
, from
, n
);
103 EXPORT_SYMBOL(memcpy_fromio
);
105 void memcpy_toio(volatile void __iomem
*to
, const void *from
, size_t n
)
107 if (cc_platform_has(CC_ATTR_GUEST_UNROLL_STRING_IO
))
108 unrolled_memcpy_toio(to
, from
, n
);
110 string_memcpy_toio(to
, from
, n
);
112 EXPORT_SYMBOL(memcpy_toio
);
114 void memset_io(volatile void __iomem
*a
, int b
, size_t c
)
116 if (cc_platform_has(CC_ATTR_GUEST_UNROLL_STRING_IO
)) {
117 unrolled_memset_io(a
, b
, c
);
120 * TODO: memset can mangle the IO patterns quite a bit.
121 * perhaps it would be better to use a dumb one:
123 memset((void *)a
, b
, c
);
126 EXPORT_SYMBOL(memset_io
);