mn10300: copy_from_user() should zero on access_ok() failure...
[pandora-kernel.git] / 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 <linux/string.h>
13 #include <linux/uaccess.h>
14
15 unsigned long
16 __generic_copy_to_user(void *to, const void *from, unsigned long n)
17 {
18         if (access_ok(VERIFY_WRITE, to, n))
19                 __copy_user(to, from, n);
20         return n;
21 }
22
23 unsigned long
24 __generic_copy_from_user(void *to, const void *from, unsigned long n)
25 {
26         if (access_ok(VERIFY_READ, from, n))
27                 __copy_user_zeroing(to, from, n);
28         else
29                 memset(to, 0, n);
30         return n;
31 }
32
33 /*
34  * Copy a null terminated string from userspace.
35  */
36 #define __do_strncpy_from_user(dst, src, count, res)            \
37 do {                                                            \
38         int w;                                                  \
39         asm volatile(                                           \
40                 "       mov     %1,%0\n"                        \
41                 "       cmp     0,%1\n"                         \
42                 "       beq     2f\n"                           \
43                 "0:\n"                                          \
44                 "       movbu   (%5),%2\n"                      \
45                 "1:\n"                                          \
46                 "       movbu   %2,(%6)\n"                      \
47                 "       inc     %5\n"                           \
48                 "       inc     %6\n"                           \
49                 "       cmp     0,%2\n"                         \
50                 "       beq     2f\n"                           \
51                 "       add     -1,%1\n"                        \
52                 "       bne     0b\n"                           \
53                 "2:\n"                                          \
54                 "       sub     %1,%0\n"                        \
55                 "3:\n"                                          \
56                 "       .section .fixup,\"ax\"\n"               \
57                 "4:\n"                                          \
58                 "       mov     %3,%0\n"                        \
59                 "       jmp     3b\n"                           \
60                 "       .previous\n"                            \
61                 "       .section __ex_table,\"a\"\n"            \
62                 "       .balign 4\n"                            \
63                 "       .long 0b,4b\n"                          \
64                 "       .long 1b,4b\n"                          \
65                 "       .previous"                              \
66                 :"=&r"(res), "=r"(count), "=&r"(w)              \
67                 :"i"(-EFAULT), "1"(count), "a"(src), "a"(dst)   \
68                 : "memory", "cc");                                      \
69 } while (0)
70
71 long
72 __strncpy_from_user(char *dst, const char *src, long count)
73 {
74         long res;
75         __do_strncpy_from_user(dst, src, count, res);
76         return res;
77 }
78
79 long
80 strncpy_from_user(char *dst, const char *src, long count)
81 {
82         long res = -EFAULT;
83         if (access_ok(VERIFY_READ, src, 1))
84                 __do_strncpy_from_user(dst, src, count, res);
85         return res;
86 }
87
88
89 /*
90  * Clear a userspace memory
91  */
92 #define __do_clear_user(addr, size)             \
93 do {                                            \
94         int w;                                  \
95         asm volatile(                           \
96                 "       cmp 0,%0\n"             \
97                 "       beq 1f\n"               \
98                 "       clr %1\n"               \
99                 "0:     movbu %1,(%3,%2)\n"     \
100                 "       inc %3\n"               \
101                 "       cmp %0,%3\n"            \
102                 "       bne 0b\n"               \
103                 "1:\n"                          \
104                 "       sub %3,%0\n"            \
105                 "2:\n"                          \
106                 ".section .fixup,\"ax\"\n"      \
107                 "3:     jmp 2b\n"               \
108                 ".previous\n"                   \
109                 ".section __ex_table,\"a\"\n"   \
110                 "       .balign 4\n"            \
111                 "       .long 0b,3b\n"          \
112                 ".previous\n"                   \
113                 : "+r"(size), "=&r"(w)          \
114                 : "a"(addr), "d"(0)             \
115                 : "memory", "cc");              \
116 } while (0)
117
118 unsigned long
119 __clear_user(void *to, unsigned long n)
120 {
121         __do_clear_user(to, n);
122         return n;
123 }
124
125 unsigned long
126 clear_user(void *to, unsigned long n)
127 {
128         if (access_ok(VERIFY_WRITE, to, n))
129                 __do_clear_user(to, n);
130         return n;
131 }
132
133 /*
134  * Return the size of a string (including the ending 0)
135  *
136  * Return 0 on exception, a value greater than N if too long
137  */
138 long strnlen_user(const char *s, long n)
139 {
140         unsigned long res, w;
141
142         if (!__addr_ok(s))
143                 return 0;
144
145         if (n < 0 || n + (u_long) s > current_thread_info()->addr_limit.seg)
146                 n = current_thread_info()->addr_limit.seg - (u_long)s;
147
148         asm volatile(
149                 "0:     cmp %4,%0\n"
150                 "       beq 2f\n"
151                 "1:     movbu (%0,%3),%1\n"
152                 "       inc %0\n"
153                 "       cmp 0,%1\n"
154                 "       beq 3f\n"
155                 "       bra 0b\n"
156                 "2:     clr %0\n"
157                 "3:\n"
158                 ".section .fixup,\"ax\"\n"
159                 "4:     jmp 2b\n"
160                 ".previous\n"
161                 ".section __ex_table,\"a\"\n"
162                 "       .balign 4\n"
163                 "       .long 1b,4b\n"
164                 ".previous\n"
165                 :"=d"(res), "=&r"(w)
166                 :"0"(0), "a"(s), "r"(n)
167                 : "memory", "cc");
168         return res;
169 }