~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/arch/x86/lib/iomem.c

Version: ~ [ linux-6.11-rc3 ] ~ [ linux-6.10.4 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.45 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.104 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.164 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.223 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.281 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.319 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 #include <linux/string.h>
  2 #include <linux/module.h>
  3 #include <linux/io.h>
  4 #include <linux/kmsan-checks.h>
  5 
  6 #define movs(type,to,from) \
  7         asm volatile("movs" type:"=&D" (to), "=&S" (from):"" (to), "1" (from):"memory")
  8 
  9 /* Originally from i386/string.h */
 10 static __always_inline void rep_movs(void *to, const void *from, size_t n)
 11 {
 12         unsigned long d0, d1, d2;
 13         asm volatile("rep ; movsl\n\t"
 14                      "testb $2,%b4\n\t"
 15                      "je 1f\n\t"
 16                      "movsw\n"
 17                      "1:\ttestb $1,%b4\n\t"
 18                      "je 2f\n\t"
 19                      "movsb\n"
 20                      "2:"
 21                      : "=&c" (d0), "=&D" (d1), "=&S" (d2)
 22                      : "" (n / 4), "q" (n), "1" ((long)to), "2" ((long)from)
 23                      : "memory");
 24 }
 25 
 26 static void string_memcpy_fromio(void *to, const volatile void __iomem *from, size_t n)
 27 {
 28         const void *orig_to = to;
 29         const size_t orig_n = n;
 30 
 31         if (unlikely(!n))
 32                 return;
 33 
 34         /* Align any unaligned source IO */
 35         if (unlikely(1 & (unsigned long)from)) {
 36                 movs("b", to, from);
 37                 n--;
 38         }
 39         if (n > 1 && unlikely(2 & (unsigned long)from)) {
 40                 movs("w", to, from);
 41                 n-=2;
 42         }
 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);
 46 }
 47 
 48 static void string_memcpy_toio(volatile void __iomem *to, const void *from, size_t n)
 49 {
 50         if (unlikely(!n))
 51                 return;
 52 
 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)) {
 57                 movs("b", to, from);
 58                 n--;
 59         }
 60         if (n > 1 && unlikely(2 & (unsigned long)to)) {
 61                 movs("w", to, from);
 62                 n-=2;
 63         }
 64         rep_movs((void *)to, (const void *) from, n);
 65 }
 66 
 67 static void unrolled_memcpy_fromio(void *to, const volatile void __iomem *from, size_t n)
 68 {
 69         const volatile char __iomem *in = from;
 70         char *out = to;
 71         int i;
 72 
 73         for (i = 0; i < n; ++i)
 74                 out[i] = readb(&in[i]);
 75 }
 76 
 77 static void unrolled_memcpy_toio(volatile void __iomem *to, const void *from, size_t n)
 78 {
 79         volatile char __iomem *out = to;
 80         const char *in = from;
 81         int i;
 82 
 83         for (i = 0; i < n; ++i)
 84                 writeb(in[i], &out[i]);
 85 }
 86 
 87 static void unrolled_memset_io(volatile void __iomem *a, int b, size_t c)
 88 {
 89         volatile char __iomem *mem = a;
 90         int i;
 91 
 92         for (i = 0; i < c; ++i)
 93                 writeb(b, &mem[i]);
 94 }
 95 
 96 void memcpy_fromio(void *to, const volatile void __iomem *from, size_t n)
 97 {
 98         if (cc_platform_has(CC_ATTR_GUEST_UNROLL_STRING_IO))
 99                 unrolled_memcpy_fromio(to, from, n);
100         else
101                 string_memcpy_fromio(to, from, n);
102 }
103 EXPORT_SYMBOL(memcpy_fromio);
104 
105 void memcpy_toio(volatile void __iomem *to, const void *from, size_t n)
106 {
107         if (cc_platform_has(CC_ATTR_GUEST_UNROLL_STRING_IO))
108                 unrolled_memcpy_toio(to, from, n);
109         else
110                 string_memcpy_toio(to, from, n);
111 }
112 EXPORT_SYMBOL(memcpy_toio);
113 
114 void memset_io(volatile void __iomem *a, int b, size_t c)
115 {
116         if (cc_platform_has(CC_ATTR_GUEST_UNROLL_STRING_IO)) {
117                 unrolled_memset_io(a, b, c);
118         } else {
119                 /*
120                  * TODO: memset can mangle the IO patterns quite a bit.
121                  * perhaps it would be better to use a dumb one:
122                  */
123                 memset((void *)a, b, c);
124         }
125 }
126 EXPORT_SYMBOL(memset_io);
127 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php