more changes on original files
[linux-2.4.git] / arch / i386 / lib / usercopy.c
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         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
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
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
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
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
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
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
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  */
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 }