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
__generic_copy_to_user(void * to,const void * from,unsigned long n)15 __generic_copy_to_user(void *to, const void *from, unsigned long n)
16 {
17 BUG_ON((long) n < 0);
18 if (access_ok(VERIFY_WRITE, to, n))
19 {
20 if(n<512)
21 __copy_user(to,from,n);
22 else
23 mmx_copy_user(to,from,n);
24 }
25 return n;
26 }
27
28 unsigned long
__generic_copy_from_user(void * to,const void * from,unsigned long n)29 __generic_copy_from_user(void *to, const void *from, unsigned long n)
30 {
31 BUG_ON((long) n < 0);
32 if (access_ok(VERIFY_READ, from, n))
33 {
34 if(n<512)
35 __copy_user_zeroing(to,from,n);
36 else
37 mmx_copy_user_zeroing(to, from, n);
38 }
39 else
40 memset(to, 0, n);
41 return n;
42 }
43
44 #else
45
46 unsigned long
__generic_copy_to_user(void * to,const void * from,unsigned long n)47 __generic_copy_to_user(void *to, const void *from, unsigned long n)
48 {
49 BUG_ON((long) n < 0);
50 prefetch(from);
51 if (access_ok(VERIFY_WRITE, to, n))
52 __copy_user(to,from,n);
53 return n;
54 }
55
56 unsigned long
__generic_copy_from_user(void * to,const void * from,unsigned long n)57 __generic_copy_from_user(void *to, const void *from, unsigned long n)
58 {
59 BUG_ON((long) n < 0);
60 prefetchw(to);
61 if (access_ok(VERIFY_READ, from, n))
62 __copy_user_zeroing(to,from,n);
63 else
64 memset(to, 0, n);
65 return n;
66 }
67
68 #endif
69
70 /*
71 * Copy a null terminated string from userspace.
72 */
73
74 #define __do_strncpy_from_user(dst,src,count,res) \
75 do { \
76 int __d0, __d1, __d2; \
77 __asm__ __volatile__( \
78 " testl %1,%1\n" \
79 " jz 2f\n" \
80 "0: lodsb\n" \
81 " stosb\n" \
82 " testb %%al,%%al\n" \
83 " jz 1f\n" \
84 " decl %1\n" \
85 " jnz 0b\n" \
86 "1: subl %1,%0\n" \
87 "2:\n" \
88 ".section .fixup,\"ax\"\n" \
89 "3: movl %5,%0\n" \
90 " jmp 2b\n" \
91 ".previous\n" \
92 ".section __ex_table,\"a\"\n" \
93 " .align 4\n" \
94 " .long 0b,3b\n" \
95 ".previous" \
96 : "=d"(res), "=c"(count), "=&a" (__d0), "=&S" (__d1), \
97 "=&D" (__d2) \
98 : "i"(-EFAULT), "0"(count), "1"(count), "3"(src), "4"(dst) \
99 : "memory"); \
100 } while (0)
101
102 /**
103 * __strncpy_from_user: - Copy a NUL terminated string from userspace, with less checking.
104 * @dst: Destination address, in kernel space. This buffer must be at
105 * least @count bytes long.
106 * @src: Source address, in user space.
107 * @count: Maximum number of bytes to copy, including the trailing NUL.
108 *
109 * Copies a NUL-terminated string from userspace to kernel space.
110 * Caller must check the specified block with access_ok() before calling
111 * this function.
112 *
113 * On success, returns the length of the string (not including the trailing
114 * NUL).
115 *
116 * If access to userspace fails, returns -EFAULT (some data may have been
117 * copied).
118 *
119 * If @count is smaller than the length of the string, copies @count bytes
120 * and returns @count.
121 */
122 long
__strncpy_from_user(char * dst,const char * src,long count)123 __strncpy_from_user(char *dst, const char *src, long count)
124 {
125 long res;
126 __do_strncpy_from_user(dst, src, count, res);
127 return res;
128 }
129
130 /**
131 * strncpy_from_user: - Copy a NUL terminated string from userspace.
132 * @dst: Destination address, in kernel space. This buffer must be at
133 * least @count bytes long.
134 * @src: Source address, in user space.
135 * @count: Maximum number of bytes to copy, including the trailing NUL.
136 *
137 * Copies a NUL-terminated string from userspace to kernel space.
138 *
139 * On success, returns the length of the string (not including the trailing
140 * NUL).
141 *
142 * If access to userspace fails, returns -EFAULT (some data may have been
143 * copied).
144 *
145 * If @count is smaller than the length of the string, copies @count bytes
146 * and returns @count.
147 */
148 long
strncpy_from_user(char * dst,const char * src,long count)149 strncpy_from_user(char *dst, const char *src, long count)
150 {
151 long res = -EFAULT;
152 if (access_ok(VERIFY_READ, src, 1))
153 __do_strncpy_from_user(dst, src, count, res);
154 return res;
155 }
156
157
158 /*
159 * Zero Userspace
160 */
161
162 #define __do_clear_user(addr,size) \
163 do { \
164 int __d0; \
165 __asm__ __volatile__( \
166 "0: rep; stosl\n" \
167 " movl %2,%0\n" \
168 "1: rep; stosb\n" \
169 "2:\n" \
170 ".section .fixup,\"ax\"\n" \
171 "3: lea 0(%2,%0,4),%0\n" \
172 " jmp 2b\n" \
173 ".previous\n" \
174 ".section __ex_table,\"a\"\n" \
175 " .align 4\n" \
176 " .long 0b,3b\n" \
177 " .long 1b,2b\n" \
178 ".previous" \
179 : "=&c"(size), "=&D" (__d0) \
180 : "r"(size & 3), "0"(size / 4), "1"(addr), "a"(0)); \
181 } while (0)
182
183 /**
184 * clear_user: - Zero a block of memory in user space.
185 * @to: Destination address, in user space.
186 * @n: Number of bytes to zero.
187 *
188 * Zero a block of memory in user space.
189 *
190 * Returns number of bytes that could not be cleared.
191 * On success, this will be zero.
192 */
193 unsigned long
clear_user(void * to,unsigned long n)194 clear_user(void *to, unsigned long n)
195 {
196 if (access_ok(VERIFY_WRITE, to, n))
197 __do_clear_user(to, n);
198 return n;
199 }
200
201 /**
202 * __clear_user: - Zero a block of memory in user space, with less checking.
203 * @to: Destination address, in user space.
204 * @n: Number of bytes to zero.
205 *
206 * Zero a block of memory in user space. Caller must check
207 * the specified block with access_ok() before calling this function.
208 *
209 * Returns number of bytes that could not be cleared.
210 * On success, this will be zero.
211 */
212 unsigned long
__clear_user(void * to,unsigned long n)213 __clear_user(void *to, unsigned long n)
214 {
215 __do_clear_user(to, n);
216 return n;
217 }
218
219 /**
220 * strlen_user: - Get the size of a string in user space.
221 * @str: The string to measure.
222 * @n: The maximum valid length
223 *
224 * Get the size of a NUL-terminated string in user space.
225 *
226 * Returns the size of the string INCLUDING the terminating NUL.
227 * On exception, returns 0.
228 * If the string is too long, returns a value greater than @n.
229 */
strnlen_user(const char * s,long n)230 long strnlen_user(const char *s, long n)
231 {
232 unsigned long mask = -__addr_ok(s);
233 unsigned long res, tmp;
234
235 __asm__ __volatile__(
236 " testl %0, %0\n"
237 " jz 3f\n"
238 " andl %0,%%ecx\n"
239 "0: repne; scasb\n"
240 " setne %%al\n"
241 " subl %%ecx,%0\n"
242 " addl %0,%%eax\n"
243 "1:\n"
244 ".section .fixup,\"ax\"\n"
245 "2: xorl %%eax,%%eax\n"
246 " jmp 1b\n"
247 "3: movb $1,%%al\n"
248 " jmp 1b\n"
249 ".previous\n"
250 ".section __ex_table,\"a\"\n"
251 " .align 4\n"
252 " .long 0b,2b\n"
253 ".previous"
254 :"=r" (n), "=D" (s), "=a" (res), "=c" (tmp)
255 :"0" (n), "1" (s), "2" (0), "3" (mask)
256 :"cc");
257 return res & mask;
258 }
259