198bbf15f644985622373893daa484e61ae59441
[sfrench/cifs-2.6.git] / arch / nios2 / include / asm / uaccess.h
1 /*
2  * User space memory access functions for Nios II
3  *
4  * Copyright (C) 2010-2011, Tobias Klauser <tklauser@distanz.ch>
5  * Copyright (C) 2009, Wind River Systems Inc
6  *   Implemented by fredrik.markstrom@gmail.com and ivarholmqvist@gmail.com
7  *
8  * This file is subject to the terms and conditions of the GNU General Public
9  * License.  See the file "COPYING" in the main directory of this archive
10  * for more details.
11  */
12
13 #ifndef _ASM_NIOS2_UACCESS_H
14 #define _ASM_NIOS2_UACCESS_H
15
16 #include <linux/string.h>
17
18 #include <asm/page.h>
19
20 /*
21  * The exception table consists of pairs of addresses: the first is the
22  * address of an instruction that is allowed to fault, and the second is
23  * the address at which the program should continue.  No registers are
24  * modified, so it is entirely up to the continuation code to figure out
25  * what to do.
26  *
27  * All the routines below use bits of fixup code that are out of line
28  * with the main instruction path.  This means when everything is well,
29  * we don't even have to jump over them.  Further, they do not intrude
30  * on our cache or tlb entries.
31  */
32 struct exception_table_entry {
33         unsigned long insn;
34         unsigned long fixup;
35 };
36
37 extern int fixup_exception(struct pt_regs *regs);
38
39 /*
40  * Segment stuff
41  */
42 #define MAKE_MM_SEG(s)          ((mm_segment_t) { (s) })
43 #define USER_DS                 MAKE_MM_SEG(0x80000000UL)
44 #define KERNEL_DS               MAKE_MM_SEG(0)
45
46 #define get_ds()                (KERNEL_DS)
47
48 #define get_fs()                (current_thread_info()->addr_limit)
49 #define set_fs(seg)             (current_thread_info()->addr_limit = (seg))
50
51 #define segment_eq(a, b)        ((a).seg == (b).seg)
52
53 #define __access_ok(addr, len)                  \
54         (((signed long)(((long)get_fs().seg) &  \
55                 ((long)(addr) | (((long)(addr)) + (len)) | (len)))) == 0)
56
57 #define access_ok(type, addr, len)              \
58         likely(__access_ok((unsigned long)(addr), (unsigned long)(len)))
59
60 # define __EX_TABLE_SECTION     ".section __ex_table,\"a\"\n"
61
62 /*
63  * Zero Userspace
64  */
65
66 static inline unsigned long __must_check __clear_user(void __user *to,
67                                                       unsigned long n)
68 {
69         __asm__ __volatile__ (
70                 "1:     stb     zero, 0(%1)\n"
71                 "       addi    %0, %0, -1\n"
72                 "       addi    %1, %1, 1\n"
73                 "       bne     %0, zero, 1b\n"
74                 "2:\n"
75                 __EX_TABLE_SECTION
76                 ".word  1b, 2b\n"
77                 ".previous\n"
78                 : "=r" (n), "=r" (to)
79                 : "0" (n), "1" (to)
80         );
81
82         return n;
83 }
84
85 static inline unsigned long __must_check clear_user(void __user *to,
86                                                     unsigned long n)
87 {
88         if (!access_ok(VERIFY_WRITE, to, n))
89                 return n;
90         return __clear_user(to, n);
91 }
92
93 extern long __copy_from_user(void *to, const void __user *from,
94                                 unsigned long n);
95 extern long __copy_to_user(void __user *to, const void *from, unsigned long n);
96
97 static inline long copy_from_user(void *to, const void __user *from,
98                                 unsigned long n)
99 {
100         unsigned long res = n;
101         if (access_ok(VERIFY_READ, from, n))
102                 res = __copy_from_user(to, from, n);
103         if (unlikely(res))
104                 memset(to + (n - res), 0, res);
105         return res;
106 }
107
108 static inline long copy_to_user(void __user *to, const void *from,
109                                 unsigned long n)
110 {
111         if (!access_ok(VERIFY_WRITE, to, n))
112                 return n;
113         return __copy_to_user(to, from, n);
114 }
115
116 extern long strncpy_from_user(char *__to, const char __user *__from,
117                                 long __len);
118 extern long strnlen_user(const char __user *s, long n);
119
120 #define __copy_from_user_inatomic       __copy_from_user
121 #define __copy_to_user_inatomic         __copy_to_user
122
123 /* Optimized macros */
124 #define __get_user_asm(val, insn, addr, err)                            \
125 {                                                                       \
126         __asm__ __volatile__(                                           \
127         "       movi    %0, %3\n"                                       \
128         "1:   " insn " %1, 0(%2)\n"                                     \
129         "       movi     %0, 0\n"                                       \
130         "2:\n"                                                          \
131         "       .section __ex_table,\"a\"\n"                            \
132         "       .word 1b, 2b\n"                                         \
133         "       .previous"                                              \
134         : "=&r" (err), "=r" (val)                                       \
135         : "r" (addr), "i" (-EFAULT));                                   \
136 }
137
138 #define __get_user_unknown(val, size, ptr, err) do {                    \
139         err = 0;                                                        \
140         if (__copy_from_user(&(val), ptr, size)) {                      \
141                 err = -EFAULT;                                          \
142         }                                                               \
143         } while (0)
144
145 #define __get_user_common(val, size, ptr, err)                          \
146 do {                                                                    \
147         switch (size) {                                                 \
148         case 1:                                                         \
149                 __get_user_asm(val, "ldbu", ptr, err);                  \
150                 break;                                                  \
151         case 2:                                                         \
152                 __get_user_asm(val, "ldhu", ptr, err);                  \
153                 break;                                                  \
154         case 4:                                                         \
155                 __get_user_asm(val, "ldw", ptr, err);                   \
156                 break;                                                  \
157         default:                                                        \
158                 __get_user_unknown(val, size, ptr, err);                \
159                 break;                                                  \
160         }                                                               \
161 } while (0)
162
163 #define __get_user(x, ptr)                                              \
164         ({                                                              \
165         long __gu_err = -EFAULT;                                        \
166         const __typeof__(*(ptr)) __user *__gu_ptr = (ptr);              \
167         unsigned long __gu_val = 0;                                     \
168         __get_user_common(__gu_val, sizeof(*(ptr)), __gu_ptr, __gu_err);\
169         (x) = (__force __typeof__(x))__gu_val;                          \
170         __gu_err;                                                       \
171         })
172
173 #define get_user(x, ptr)                                                \
174 ({                                                                      \
175         long __gu_err = -EFAULT;                                        \
176         const __typeof__(*(ptr)) __user *__gu_ptr = (ptr);              \
177         unsigned long __gu_val = 0;                                     \
178         if (access_ok(VERIFY_READ,  __gu_ptr, sizeof(*__gu_ptr)))       \
179                 __get_user_common(__gu_val, sizeof(*__gu_ptr),          \
180                         __gu_ptr, __gu_err);                            \
181         (x) = (__force __typeof__(x))__gu_val;                          \
182         __gu_err;                                                       \
183 })
184
185 #define __put_user_asm(val, insn, ptr, err)                             \
186 {                                                                       \
187         __asm__ __volatile__(                                           \
188         "       movi    %0, %3\n"                                       \
189         "1:   " insn " %1, 0(%2)\n"                                     \
190         "       movi     %0, 0\n"                                       \
191         "2:\n"                                                          \
192         "       .section __ex_table,\"a\"\n"                            \
193         "       .word 1b, 2b\n"                                         \
194         "       .previous\n"                                            \
195         : "=&r" (err)                                                   \
196         : "r" (val), "r" (ptr), "i" (-EFAULT));                         \
197 }
198
199 #define put_user(x, ptr)                                                \
200 ({                                                                      \
201         long __pu_err = -EFAULT;                                        \
202         __typeof__(*(ptr)) __user *__pu_ptr = (ptr);                    \
203         __typeof__(*(ptr)) __pu_val = (__typeof(*ptr))(x);              \
204         if (access_ok(VERIFY_WRITE, __pu_ptr, sizeof(*__pu_ptr))) {     \
205                 switch (sizeof(*__pu_ptr)) {                            \
206                 case 1:                                                 \
207                         __put_user_asm(__pu_val, "stb", __pu_ptr, __pu_err); \
208                         break;                                          \
209                 case 2:                                                 \
210                         __put_user_asm(__pu_val, "sth", __pu_ptr, __pu_err); \
211                         break;                                          \
212                 case 4:                                                 \
213                         __put_user_asm(__pu_val, "stw", __pu_ptr, __pu_err); \
214                         break;                                          \
215                 default:                                                \
216                         /* XXX: This looks wrong... */                  \
217                         __pu_err = 0;                                   \
218                         if (copy_to_user(__pu_ptr, &(__pu_val),         \
219                                 sizeof(*__pu_ptr)))                     \
220                                 __pu_err = -EFAULT;                     \
221                         break;                                          \
222                 }                                                       \
223         }                                                               \
224         __pu_err;                                                       \
225 })
226
227 #define __put_user(x, ptr) put_user(x, ptr)
228
229 #endif /* _ASM_NIOS2_UACCESS_H */