diff options
Diffstat (limited to 'include/asm-frv/uaccess.h')
-rw-r--r-- | include/asm-frv/uaccess.h | 318 |
1 files changed, 318 insertions, 0 deletions
diff --git a/include/asm-frv/uaccess.h b/include/asm-frv/uaccess.h new file mode 100644 index 000000000000..32dc52e883e5 --- /dev/null +++ b/include/asm-frv/uaccess.h | |||
@@ -0,0 +1,318 @@ | |||
1 | /* uaccess.h: userspace accessor functions | ||
2 | * | ||
3 | * Copyright (C) 2004 Red Hat, Inc. All Rights Reserved. | ||
4 | * Written by David Howells (dhowells@redhat.com) | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of the GNU General Public License | ||
8 | * as published by the Free Software Foundation; either version | ||
9 | * 2 of the License, or (at your option) any later version. | ||
10 | */ | ||
11 | |||
12 | #ifndef _ASM_UACCESS_H | ||
13 | #define _ASM_UACCESS_H | ||
14 | |||
15 | /* | ||
16 | * User space memory access functions | ||
17 | */ | ||
18 | #include <linux/sched.h> | ||
19 | #include <linux/mm.h> | ||
20 | #include <asm/segment.h> | ||
21 | #include <asm/sections.h> | ||
22 | |||
23 | #define HAVE_ARCH_UNMAPPED_AREA /* we decide where to put mmaps */ | ||
24 | |||
25 | #define __ptr(x) ((unsigned long *)(x)) | ||
26 | |||
27 | #define VERIFY_READ 0 | ||
28 | #define VERIFY_WRITE 1 | ||
29 | |||
30 | #define __addr_ok(addr) ((unsigned long)(addr) < get_addr_limit()) | ||
31 | |||
32 | /* | ||
33 | * check that a range of addresses falls within the current address limit | ||
34 | */ | ||
35 | static inline int ___range_ok(unsigned long addr, unsigned long size) | ||
36 | { | ||
37 | #ifdef CONFIG_MMU | ||
38 | int flag = -EFAULT, tmp; | ||
39 | |||
40 | asm volatile ( | ||
41 | " addcc %3,%2,%1,icc0 \n" /* set C-flag if addr+size>4GB */ | ||
42 | " subcc.p %1,%4,gr0,icc1 \n" /* jump if addr+size>limit */ | ||
43 | " bc icc0,#0,0f \n" | ||
44 | " bhi icc1,#0,0f \n" | ||
45 | " setlos #0,%0 \n" /* mark okay */ | ||
46 | "0: \n" | ||
47 | : "=r"(flag), "=&r"(tmp) | ||
48 | : "r"(addr), "r"(size), "r"(get_addr_limit()), "0"(flag) | ||
49 | ); | ||
50 | |||
51 | return flag; | ||
52 | |||
53 | #else | ||
54 | |||
55 | if (addr < memory_start || | ||
56 | addr > memory_end || | ||
57 | size > memory_end - memory_start || | ||
58 | addr + size > memory_end) | ||
59 | return -EFAULT; | ||
60 | |||
61 | return 0; | ||
62 | #endif | ||
63 | } | ||
64 | |||
65 | #define __range_ok(addr,size) ___range_ok((unsigned long) (addr), (unsigned long) (size)) | ||
66 | |||
67 | #define access_ok(type,addr,size) (__range_ok((addr), (size)) == 0) | ||
68 | #define __access_ok(addr,size) (__range_ok((addr), (size)) == 0) | ||
69 | |||
70 | /* this function will go away soon - use access_ok() / __range_ok() instead */ | ||
71 | static inline int __deprecated verify_area(int type, const void * addr, unsigned long size) | ||
72 | { | ||
73 | return __range_ok(addr, size); | ||
74 | } | ||
75 | |||
76 | /* | ||
77 | * The exception table consists of pairs of addresses: the first is the | ||
78 | * address of an instruction that is allowed to fault, and the second is | ||
79 | * the address at which the program should continue. No registers are | ||
80 | * modified, so it is entirely up to the continuation code to figure out | ||
81 | * what to do. | ||
82 | * | ||
83 | * All the routines below use bits of fixup code that are out of line | ||
84 | * with the main instruction path. This means when everything is well, | ||
85 | * we don't even have to jump over them. Further, they do not intrude | ||
86 | * on our cache or tlb entries. | ||
87 | */ | ||
88 | struct exception_table_entry | ||
89 | { | ||
90 | unsigned long insn, fixup; | ||
91 | }; | ||
92 | |||
93 | /* Returns 0 if exception not found and fixup otherwise. */ | ||
94 | extern unsigned long search_exception_table(unsigned long); | ||
95 | |||
96 | |||
97 | /* | ||
98 | * These are the main single-value transfer routines. They automatically | ||
99 | * use the right size if we just have the right pointer type. | ||
100 | */ | ||
101 | #define __put_user(x, ptr) \ | ||
102 | ({ \ | ||
103 | int __pu_err = 0; \ | ||
104 | \ | ||
105 | typeof(*(ptr)) __pu_val = (x); \ | ||
106 | \ | ||
107 | switch (sizeof (*(ptr))) { \ | ||
108 | case 1: \ | ||
109 | __put_user_asm(__pu_err, __pu_val, ptr, "b", "r"); \ | ||
110 | break; \ | ||
111 | case 2: \ | ||
112 | __put_user_asm(__pu_err, __pu_val, ptr, "h", "r"); \ | ||
113 | break; \ | ||
114 | case 4: \ | ||
115 | __put_user_asm(__pu_err, __pu_val, ptr, "", "r"); \ | ||
116 | break; \ | ||
117 | case 8: \ | ||
118 | __put_user_asm(__pu_err, __pu_val, ptr, "d", "e"); \ | ||
119 | break; \ | ||
120 | default: \ | ||
121 | __pu_err = __put_user_bad(); \ | ||
122 | break; \ | ||
123 | } \ | ||
124 | __pu_err; \ | ||
125 | }) | ||
126 | |||
127 | #define put_user(x, ptr) \ | ||
128 | ({ \ | ||
129 | typeof(&*ptr) _p = (ptr); \ | ||
130 | int _e; \ | ||
131 | \ | ||
132 | _e = __range_ok(_p, sizeof(*_p)); \ | ||
133 | if (_e == 0) \ | ||
134 | _e = __put_user((x), _p); \ | ||
135 | _e; \ | ||
136 | }) | ||
137 | |||
138 | extern int __put_user_bad(void); | ||
139 | |||
140 | /* | ||
141 | * Tell gcc we read from memory instead of writing: this is because | ||
142 | * we do not write to any memory gcc knows about, so there are no | ||
143 | * aliasing issues. | ||
144 | */ | ||
145 | |||
146 | #ifdef CONFIG_MMU | ||
147 | |||
148 | #define __put_user_asm(err,x,ptr,dsize,constraint) \ | ||
149 | do { \ | ||
150 | asm volatile("1: st"dsize"%I1 %2,%M1 \n" \ | ||
151 | "2: \n" \ | ||
152 | ".subsection 2 \n" \ | ||
153 | "3: setlos %3,%0 \n" \ | ||
154 | " bra 2b \n" \ | ||
155 | ".previous \n" \ | ||
156 | ".section __ex_table,\"a\" \n" \ | ||
157 | " .balign 8 \n" \ | ||
158 | " .long 1b,3b \n" \ | ||
159 | ".previous" \ | ||
160 | : "=r" (err) \ | ||
161 | : "m" (*__ptr(ptr)), constraint (x), "i"(-EFAULT), "0"(err) \ | ||
162 | : "memory"); \ | ||
163 | } while (0) | ||
164 | |||
165 | #else | ||
166 | |||
167 | #define __put_user_asm(err,x,ptr,bwl,con) \ | ||
168 | do { \ | ||
169 | asm(" st"bwl"%I0 %1,%M0 \n" \ | ||
170 | " membar \n" \ | ||
171 | : \ | ||
172 | : "m" (*__ptr(ptr)), con (x) \ | ||
173 | : "memory"); \ | ||
174 | } while (0) | ||
175 | |||
176 | #endif | ||
177 | |||
178 | /*****************************************************************************/ | ||
179 | /* | ||
180 | * | ||
181 | */ | ||
182 | #define __get_user(x, ptr) \ | ||
183 | ({ \ | ||
184 | typeof(*(ptr)) __gu_val = 0; \ | ||
185 | int __gu_err = 0; \ | ||
186 | \ | ||
187 | switch (sizeof(*(ptr))) { \ | ||
188 | case 1: \ | ||
189 | __get_user_asm(__gu_err, __gu_val, ptr, "ub", "=r"); \ | ||
190 | break; \ | ||
191 | case 2: \ | ||
192 | __get_user_asm(__gu_err, __gu_val, ptr, "uh", "=r"); \ | ||
193 | break; \ | ||
194 | case 4: \ | ||
195 | __get_user_asm(__gu_err, __gu_val, ptr, "", "=r"); \ | ||
196 | break; \ | ||
197 | case 8: \ | ||
198 | __get_user_asm(__gu_err, __gu_val, ptr, "d", "=e"); \ | ||
199 | break; \ | ||
200 | default: \ | ||
201 | __gu_err = __get_user_bad(); \ | ||
202 | break; \ | ||
203 | } \ | ||
204 | (x) = __gu_val; \ | ||
205 | __gu_err; \ | ||
206 | }) | ||
207 | |||
208 | #define get_user(x, ptr) \ | ||
209 | ({ \ | ||
210 | typeof(&*ptr) _p = (ptr); \ | ||
211 | int _e; \ | ||
212 | \ | ||
213 | _e = __range_ok(_p, sizeof(*_p)); \ | ||
214 | if (likely(_e == 0)) \ | ||
215 | _e = __get_user((x), _p); \ | ||
216 | else \ | ||
217 | (x) = (typeof(x)) 0; \ | ||
218 | _e; \ | ||
219 | }) | ||
220 | |||
221 | extern int __get_user_bad(void); | ||
222 | |||
223 | #ifdef CONFIG_MMU | ||
224 | |||
225 | #define __get_user_asm(err,x,ptr,dtype,constraint) \ | ||
226 | do { \ | ||
227 | asm("1: ld"dtype"%I2 %M2,%1 \n" \ | ||
228 | "2: \n" \ | ||
229 | ".subsection 2 \n" \ | ||
230 | "3: setlos %3,%0 \n" \ | ||
231 | " setlos #0,%1 \n" \ | ||
232 | " bra 2b \n" \ | ||
233 | ".previous \n" \ | ||
234 | ".section __ex_table,\"a\" \n" \ | ||
235 | " .balign 8 \n" \ | ||
236 | " .long 1b,3b \n" \ | ||
237 | ".previous" \ | ||
238 | : "=r" (err), constraint (x) \ | ||
239 | : "m" (*__ptr(ptr)), "i"(-EFAULT), "0"(err) \ | ||
240 | ); \ | ||
241 | } while(0) | ||
242 | |||
243 | #else | ||
244 | |||
245 | #define __get_user_asm(err,x,ptr,bwl,con) \ | ||
246 | asm(" ld"bwl"%I1 %M1,%0 \n" \ | ||
247 | " membar \n" \ | ||
248 | : con(x) \ | ||
249 | : "m" (*__ptr(ptr))) | ||
250 | |||
251 | #endif | ||
252 | |||
253 | /*****************************************************************************/ | ||
254 | /* | ||
255 | * | ||
256 | */ | ||
257 | #ifdef CONFIG_MMU | ||
258 | extern long __memset_user(void *dst, unsigned long count); | ||
259 | extern long __memcpy_user(void *dst, const void *src, unsigned long count); | ||
260 | |||
261 | #define clear_user(dst,count) __memset_user((dst), (count)) | ||
262 | #define __copy_from_user_inatomic(to, from, n) __memcpy_user((to), (from), (n)) | ||
263 | #define __copy_to_user_inatomic(to, from, n) __memcpy_user((to), (from), (n)) | ||
264 | |||
265 | #else | ||
266 | |||
267 | #define clear_user(dst,count) (memset((dst), 0, (count)), 0) | ||
268 | #define __copy_from_user_inatomic(to, from, n) (memcpy((to), (from), (n)), 0) | ||
269 | #define __copy_to_user_inatomic(to, from, n) (memcpy((to), (from), (n)), 0) | ||
270 | |||
271 | #endif | ||
272 | |||
273 | static inline unsigned long __must_check | ||
274 | __copy_to_user(void __user *to, const void *from, unsigned long n) | ||
275 | { | ||
276 | might_sleep(); | ||
277 | return __copy_to_user_inatomic(to, from, n); | ||
278 | } | ||
279 | |||
280 | static inline unsigned long | ||
281 | __copy_from_user(void *to, const void __user *from, unsigned long n) | ||
282 | { | ||
283 | might_sleep(); | ||
284 | return __copy_from_user_inatomic(to, from, n); | ||
285 | } | ||
286 | |||
287 | static inline long copy_from_user(void *to, const void *from, unsigned long n) | ||
288 | { | ||
289 | unsigned long ret = n; | ||
290 | |||
291 | if (likely(__access_ok(from, n))) | ||
292 | ret = __copy_from_user(to, from, n); | ||
293 | |||
294 | if (unlikely(ret != 0)) | ||
295 | memset(to + (n - ret), 0, ret); | ||
296 | |||
297 | return ret; | ||
298 | } | ||
299 | |||
300 | static inline long copy_to_user(void *to, const void *from, unsigned long n) | ||
301 | { | ||
302 | return likely(__access_ok(to, n)) ? __copy_to_user(to, from, n) : n; | ||
303 | } | ||
304 | |||
305 | #define copy_to_user_ret(to,from,n,retval) ({ if (copy_to_user(to,from,n)) return retval; }) | ||
306 | #define copy_from_user_ret(to,from,n,retval) ({ if (copy_from_user(to,from,n)) return retval; }) | ||
307 | |||
308 | extern long strncpy_from_user(char *dst, const char *src, long count); | ||
309 | extern long strnlen_user(const char *src, long count); | ||
310 | |||
311 | #define strlen_user(str) strnlen_user(str, 32767) | ||
312 | |||
313 | extern unsigned long search_exception_table(unsigned long addr); | ||
314 | |||
315 | #define copy_to_user_page(vma, page, vaddr, dst, src, len) memcpy(dst, src, len) | ||
316 | #define copy_from_user_page(vma, page, vaddr, dst, src, len) memcpy(dst, src, len) | ||
317 | |||
318 | #endif /* _ASM_UACCESS_H */ | ||