|
|
1 /*
2 * User address space access functions.
3 * The non inlined parts of asm-i386/uaccess.h are here.
4 *
5 * Copyright 1997 Andi Kleen <ak@muc.de>
6 * Copyright 1997 Linus Torvalds
7 */
8 #include <linux/config.h>
9 #include <asm/uaccess.h>
10 #include <asm/mmx.h>
11
12 #ifdef CONFIG_X86_USE_3DNOW_AND_WORKS
13
14 unsigned long
15 __generic_copy_to_user(void *to, const void *from, unsigned long n)
16 {
17 if (access_ok(VERIFY_WRITE, to, n))
18 {
19 if(n<512)
20 __copy_user(to,from,n);
21 else
22 mmx_copy_user(to,from,n);
23 }
24 return n;
25 }
26
27 unsigned long
28 __generic_copy_from_user(void *to, const void *from, unsigned long n)
29 {
30 if (access_ok(VERIFY_READ, from, n))
31 {
32 if(n<512)
33 __copy_user_zeroing(to,from,n);
34 else
35 mmx_copy_user_zeroing(to, from, n);
36 }
37 else
38 memset(to, 0, n);
39 return n;
40 }
41
42 #else
43
44 unsigned long
45 __generic_copy_to_user(void *to, const void *from, unsigned long n)
46 {
47 prefetch(from);
48 if (access_ok(VERIFY_WRITE, to, n))
49 __copy_user(to,from,n);
50 return n;
51 }
52
53 unsigned long
54 __generic_copy_from_user(void *to, const void *from, unsigned long n)
55 {
56 prefetchw(to);
57 if (access_ok(VERIFY_READ, from, n))
58 __copy_user_zeroing(to,from,n);
59 else
60 memset(to, 0, n);
61 return n;
62 }
63
64 #endif
65
66 /*
67 * Copy a null terminated string from userspace.
68 */
69
70 #define __do_strncpy_from_user(dst,src,count,res) \
71 do { \
72 int __d0, __d1, __d2; \
73 __asm__ __volatile__( \
74 " testl %1,%1\n" \
75 " jz 2f\n" \
76 "0: lodsb\n" \
77 " stosb\n" \
78 " testb %%al,%%al\n" \
79 " jz 1f\n" \
80 " decl %1\n" \
81 " jnz 0b\n" \
82 "1: subl %1,%0\n" \
83 "2:\n" \
84 ".section .fixup,\"ax\"\n" \
85 "3: movl %5,%0\n" \
86 " jmp 2b\n" \
87 ".previous\n" \
88 ".section __ex_table,\"a\"\n" \
89 " .align 4\n" \
90 " .long 0b,3b\n" \
91 ".previous" \
92 : "=d"(res), "=c"(count), "=&a" (__d0), "=&S" (__d1), \
93 "=&D" (__d2) \
94 : "i"(-EFAULT), ""(count), "1"(count), "3"(src), "4"(dst) \
95 : "memory"); \
96 } while (0)
97
98 long
99 __strncpy_from_user(char *dst, const char *src, long count)
100 {
101 long res;
102 __do_strncpy_from_user(dst, src, count, res);
103 return res;
104 }
105
106 long
107 strncpy_from_user(char *dst, const char *src, long count)
108 {
109 long res = -EFAULT;
110 if (access_ok(VERIFY_READ, src, 1))
111 __do_strncpy_from_user(dst, src, count, res);
112 return res;
113 }
114
115
116 /*
117 * Zero Userspace
118 */
119
120 #define __do_clear_user(addr,size) \
121 do { \
122 int __d0; \
123 __asm__ __volatile__( \
124 "0: rep; stosl\n" \
125 " movl %2,%0\n" \
126 "1: rep; stosb\n" \
127 "2:\n" \
128 ".section .fixup,\"ax\"\n" \
129 "3: lea 0(%2,%0,4),%0\n" \
130 " jmp 2b\n" \
131 ".previous\n" \
132 ".section __ex_table,\"a\"\n" \
133 " .align 4\n" \
134 " .long 0b,3b\n" \
135 " .long 1b,2b\n" \
136 ".previous" \
137 : "=&c"(size), "=&D" (__d0) \
138 : "r"(size & 3), ""(size / 4), "1"(addr), "a"(0)); \
139 } while (0)
140
141 unsigned long
142 clear_user(void *to, unsigned long n)
143 {
144 if (access_ok(VERIFY_WRITE, to, n))
145 __do_clear_user(to, n);
146 return n;
147 }
148
149 unsigned long
150 __clear_user(void *to, unsigned long n)
151 {
152 __do_clear_user(to, n);
153 return n;
154 }
155
156 /*
157 * Return the size of a string (including the ending 0)
158 *
159 * Return 0 on exception, a value greater than N if too long
160 */
161
162 long strnlen_user(const char *s, long n)
163 {
164 unsigned long mask = -__addr_ok(s);
165 unsigned long res, tmp;
166
167 __asm__ __volatile__(
168 " testl %0, %0\n"
169 " jz 3f\n"
170 " andl %0,%%ecx\n"
171 "0: repne; scasb\n"
172 " setne %%al\n"
173 " subl %%ecx,%0\n"
174 " addl %0,%%eax\n"
175 "1:\n"
176 ".section .fixup,\"ax\"\n"
177 "2: xorl %%eax,%%eax\n"
178 " jmp 1b\n"
179 "3: movb $1,%%al\n"
180 " jmp 1b\n"
181 ".previous\n"
182 ".section __ex_table,\"a\"\n"
183 " .align 4\n"
184 " .long 0b,2b\n"
185 ".previous"
186 :"=r" (n), "=D" (s), "=a" (res), "=c" (tmp)
187 :"" (n), "1" (s), "2" (0), "3" (mask)
188 :"cc");
189 return res & mask;
190 }
191