Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6
[linux-2.6] / arch / mn10300 / lib / usercopy.c
1 /* MN10300 Userspace accessor functions
2  *
3  * Copyright (C) 2007 Matsushita Electric Industrial Co., Ltd.
4  * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
5  * Written by David Howells (dhowells@redhat.com)
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public Licence
9  * as published by the Free Software Foundation; either version
10  * 2 of the Licence, or (at your option) any later version.
11  */
12 #include <asm/uaccess.h>
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                 __copy_user(to, from, n);
19         return n;
20 }
21
22 unsigned long
23 __generic_copy_from_user(void *to, const void *from, unsigned long n)
24 {
25         if (access_ok(VERIFY_READ, from, n))
26                 __copy_user_zeroing(to, from, n);
27         return n;
28 }
29
30 /*
31  * Copy a null terminated string from userspace.
32  */
33 #define __do_strncpy_from_user(dst, src, count, res)            \
34 do {                                                            \
35         int w;                                                  \
36         asm volatile(                                           \
37                 "       mov     %1,%0\n"                        \
38                 "       cmp     0,%1\n"                         \
39                 "       beq     2f\n"                           \
40                 "0:\n"                                          \
41                 "       movbu   (%5),%2\n"                      \
42                 "1:\n"                                          \
43                 "       movbu   %2,(%6)\n"                      \
44                 "       inc     %5\n"                           \
45                 "       inc     %6\n"                           \
46                 "       cmp     0,%2\n"                         \
47                 "       beq     2f\n"                           \
48                 "       add     -1,%1\n"                        \
49                 "       bne     0b\n"                           \
50                 "2:\n"                                          \
51                 "       sub     %1,%0\n"                        \
52                 "3:\n"                                          \
53                 "       .section .fixup,\"ax\"\n"               \
54                 "4:\n"                                          \
55                 "       mov     %3,%0\n"                        \
56                 "       jmp     3b\n"                           \
57                 "       .previous\n"                            \
58                 "       .section __ex_table,\"a\"\n"            \
59                 "       .balign 4\n"                            \
60                 "       .long 0b,4b\n"                          \
61                 "       .long 1b,4b\n"                          \
62                 "       .previous"                              \
63                 :"=&r"(res), "=r"(count), "=&r"(w)              \
64                 :"i"(-EFAULT), "1"(count), "a"(src), "a"(dst)   \
65                 :"memory");                                     \
66 } while (0)
67
68 long
69 __strncpy_from_user(char *dst, const char *src, long count)
70 {
71         long res;
72         __do_strncpy_from_user(dst, src, count, res);
73         return res;
74 }
75
76 long
77 strncpy_from_user(char *dst, const char *src, long count)
78 {
79         long res = -EFAULT;
80         if (access_ok(VERIFY_READ, src, 1))
81                 __do_strncpy_from_user(dst, src, count, res);
82         return res;
83 }
84
85
86 /*
87  * Clear a userspace memory
88  */
89 #define __do_clear_user(addr, size)             \
90 do {                                            \
91         int w;                                  \
92         asm volatile(                           \
93                 "       cmp 0,%0\n"             \
94                 "       beq 1f\n"               \
95                 "       clr %1\n"               \
96                 "0:     movbu %1,(%3,%2)\n"     \
97                 "       inc %3\n"               \
98                 "       cmp %0,%3\n"            \
99                 "       bne 0b\n"               \
100                 "1:\n"                          \
101                 "       sub %3,%0\n"            \
102                 "2:\n"                          \
103                 ".section .fixup,\"ax\"\n"      \
104                 "3:     jmp 2b\n"               \
105                 ".previous\n"                   \
106                 ".section __ex_table,\"a\"\n"   \
107                 "       .balign 4\n"            \
108                 "       .long 0b,3b\n"          \
109                 ".previous\n"                   \
110                 : "+r"(size), "=&r"(w)          \
111                 : "a"(addr), "d"(0)             \
112                 : "memory");                    \
113 } while (0)
114
115 unsigned long
116 __clear_user(void *to, unsigned long n)
117 {
118         __do_clear_user(to, n);
119         return n;
120 }
121
122 unsigned long
123 clear_user(void *to, unsigned long n)
124 {
125         if (access_ok(VERIFY_WRITE, to, n))
126                 __do_clear_user(to, n);
127         return n;
128 }
129
130 /*
131  * Return the size of a string (including the ending 0)
132  *
133  * Return 0 on exception, a value greater than N if too long
134  */
135 long strnlen_user(const char *s, long n)
136 {
137         unsigned long res, w;
138
139         if (!__addr_ok(s))
140                 return 0;
141
142         if (n < 0 || n + (u_long) s > current_thread_info()->addr_limit.seg)
143                 n = current_thread_info()->addr_limit.seg - (u_long)s;
144
145         asm volatile(
146                 "0:     cmp %4,%0\n"
147                 "       beq 2f\n"
148                 "1:     movbu (%0,%3),%1\n"
149                 "       inc %0\n"
150                 "       cmp 0,%1\n"
151                 "       beq 3f\n"
152                 "       bra 0b\n"
153                 "2:     clr %0\n"
154                 "3:\n"
155                 ".section .fixup,\"ax\"\n"
156                 "4:     jmp 2b\n"
157                 ".previous\n"
158                 ".section __ex_table,\"a\"\n"
159                 "       .balign 4\n"
160                 "       .long 1b,4b\n"
161                 ".previous\n"
162                 :"=d"(res), "=&r"(w)
163                 :"0"(0), "a"(s), "r"(n)
164                 :"memory");
165         return res;
166 }