1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16#ifndef _XTENSA_UACCESS_H
17#define _XTENSA_UACCESS_H
18
19#include <linux/errno.h>
20#ifndef __ASSEMBLY__
21#include <linux/prefetch.h>
22#endif
23#include <asm/types.h>
24
25#define VERIFY_READ 0
26#define VERIFY_WRITE 1
27
28#ifdef __ASSEMBLY__
29
30#include <asm/current.h>
31#include <asm/asm-offsets.h>
32#include <asm/processor.h>
33
34
35
36
37
38
39
40#define KERNEL_DS 0
41#define USER_DS 1
42
43#define get_ds (KERNEL_DS)
44
45
46
47
48
49
50
51
52
53 .macro get_fs ad, sp
54 GET_CURRENT(\ad,\sp)
55#if THREAD_CURRENT_DS > 1020
56 addi \ad, \ad, TASK_THREAD
57 l32i \ad, \ad, THREAD_CURRENT_DS - TASK_THREAD
58#else
59 l32i \ad, \ad, THREAD_CURRENT_DS
60#endif
61 .endm
62
63
64
65
66
67
68
69
70
71
72
73 .macro set_fs at, av, sp
74 GET_CURRENT(\at,\sp)
75 s32i \av, \at, THREAD_CURRENT_DS
76 .endm
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98#if ((KERNEL_DS != 0) || (USER_DS == 0))
99# error Assembly macro kernel_ok fails
100#endif
101 .macro kernel_ok at, sp, success
102 get_fs \at, \sp
103 beqz \at, \success
104 .endm
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129 .macro user_ok aa, as, at, error
130 movi \at, __XTENSA_UL_CONST(TASK_SIZE)
131 bgeu \as, \at, \error
132 sub \at, \at, \as
133 bgeu \aa, \at, \error
134 .endm
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159 .macro access_ok aa, as, at, sp, error
160 kernel_ok \at, \sp, .Laccess_ok_\@
161 user_ok \aa, \as, \at, \error
162.Laccess_ok_\@:
163 .endm
164
165#else
166
167#include <linux/sched.h>
168
169
170
171
172
173
174
175
176
177
178#define KERNEL_DS ((mm_segment_t) { 0 })
179#define USER_DS ((mm_segment_t) { 1 })
180
181#define get_ds() (KERNEL_DS)
182#define get_fs() (current->thread.current_ds)
183#define set_fs(val) (current->thread.current_ds = (val))
184
185#define segment_eq(a, b) ((a).seg == (b).seg)
186
187#define __kernel_ok (segment_eq(get_fs(), KERNEL_DS))
188#define __user_ok(addr, size) \
189 (((size) <= TASK_SIZE)&&((addr) <= TASK_SIZE-(size)))
190#define __access_ok(addr, size) (__kernel_ok || __user_ok((addr), (size)))
191#define access_ok(type, addr, size) __access_ok((unsigned long)(addr), (size))
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207#define put_user(x, ptr) __put_user_check((x), (ptr), sizeof(*(ptr)))
208#define get_user(x, ptr) __get_user_check((x), (ptr), sizeof(*(ptr)))
209
210
211
212
213
214
215
216#define __put_user(x, ptr) __put_user_nocheck((x), (ptr), sizeof(*(ptr)))
217#define __get_user(x, ptr) __get_user_nocheck((x), (ptr), sizeof(*(ptr)))
218
219
220extern long __put_user_bad(void);
221
222#define __put_user_nocheck(x, ptr, size) \
223({ \
224 long __pu_err; \
225 __put_user_size((x), (ptr), (size), __pu_err); \
226 __pu_err; \
227})
228
229#define __put_user_check(x, ptr, size) \
230({ \
231 long __pu_err = -EFAULT; \
232 __typeof__(*(ptr)) *__pu_addr = (ptr); \
233 if (access_ok(VERIFY_WRITE, __pu_addr, size)) \
234 __put_user_size((x), __pu_addr, (size), __pu_err); \
235 __pu_err; \
236})
237
238#define __put_user_size(x, ptr, size, retval) \
239do { \
240 int __cb; \
241 retval = 0; \
242 switch (size) { \
243 case 1: __put_user_asm(x, ptr, retval, 1, "s8i", __cb); break; \
244 case 2: __put_user_asm(x, ptr, retval, 2, "s16i", __cb); break; \
245 case 4: __put_user_asm(x, ptr, retval, 4, "s32i", __cb); break; \
246 case 8: { \
247 __typeof__(*ptr) __v64 = x; \
248 retval = __copy_to_user(ptr, &__v64, 8); \
249 break; \
250 } \
251 default: __put_user_bad(); \
252 } \
253} while (0)
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277#define __check_align_1 ""
278
279#define __check_align_2 \
280 " _bbci.l %3, 0, 1f \n" \
281 " movi %0, %4 \n" \
282 " _j 2f \n"
283
284#define __check_align_4 \
285 " _bbsi.l %3, 0, 0f \n" \
286 " _bbci.l %3, 1, 1f \n" \
287 "0: movi %0, %4 \n" \
288 " _j 2f \n"
289
290
291
292
293
294
295
296
297
298
299#define __put_user_asm(x, addr, err, align, insn, cb) \
300__asm__ __volatile__( \
301 __check_align_##align \
302 "1: "insn" %2, %3, 0 \n" \
303 "2: \n" \
304 " .section .fixup,\"ax\" \n" \
305 " .align 4 \n" \
306 "4: \n" \
307 " .long 2b \n" \
308 "5: \n" \
309 " l32r %1, 4b \n" \
310 " movi %0, %4 \n" \
311 " jx %1 \n" \
312 " .previous \n" \
313 " .section __ex_table,\"a\" \n" \
314 " .long 1b, 5b \n" \
315 " .previous" \
316 :"=r" (err), "=r" (cb) \
317 :"r" ((int)(x)), "r" (addr), "i" (-EFAULT), "0" (err))
318
319#define __get_user_nocheck(x, ptr, size) \
320({ \
321 long __gu_err, __gu_val; \
322 __get_user_size(__gu_val, (ptr), (size), __gu_err); \
323 (x) = (__force __typeof__(*(ptr)))__gu_val; \
324 __gu_err; \
325})
326
327#define __get_user_check(x, ptr, size) \
328({ \
329 long __gu_err = -EFAULT, __gu_val = 0; \
330 const __typeof__(*(ptr)) *__gu_addr = (ptr); \
331 if (access_ok(VERIFY_READ, __gu_addr, size)) \
332 __get_user_size(__gu_val, __gu_addr, (size), __gu_err); \
333 (x) = (__force __typeof__(*(ptr)))__gu_val; \
334 __gu_err; \
335})
336
337extern long __get_user_bad(void);
338
339#define __get_user_size(x, ptr, size, retval) \
340do { \
341 int __cb; \
342 retval = 0; \
343 switch (size) { \
344 case 1: __get_user_asm(x, ptr, retval, 1, "l8ui", __cb); break;\
345 case 2: __get_user_asm(x, ptr, retval, 2, "l16ui", __cb); break;\
346 case 4: __get_user_asm(x, ptr, retval, 4, "l32i", __cb); break;\
347 case 8: retval = __copy_from_user(&x, ptr, 8); break; \
348 default: (x) = __get_user_bad(); \
349 } \
350} while (0)
351
352
353
354
355
356
357#define __get_user_asm(x, addr, err, align, insn, cb) \
358__asm__ __volatile__( \
359 __check_align_##align \
360 "1: "insn" %2, %3, 0 \n" \
361 "2: \n" \
362 " .section .fixup,\"ax\" \n" \
363 " .align 4 \n" \
364 "4: \n" \
365 " .long 2b \n" \
366 "5: \n" \
367 " l32r %1, 4b \n" \
368 " movi %2, 0 \n" \
369 " movi %0, %4 \n" \
370 " jx %1 \n" \
371 " .previous \n" \
372 " .section __ex_table,\"a\" \n" \
373 " .long 1b, 5b \n" \
374 " .previous" \
375 :"=r" (err), "=r" (cb), "=r" (x) \
376 :"r" (addr), "i" (-EFAULT), "0" (err))
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392extern unsigned __xtensa_copy_user(void *to, const void *from, unsigned n);
393#define __copy_user(to, from, size) __xtensa_copy_user(to, from, size)
394
395
396static inline unsigned long
397__generic_copy_from_user_nocheck(void *to, const void *from, unsigned long n)
398{
399 return __copy_user(to, from, n);
400}
401
402static inline unsigned long
403__generic_copy_to_user_nocheck(void *to, const void *from, unsigned long n)
404{
405 return __copy_user(to, from, n);
406}
407
408static inline unsigned long
409__generic_copy_to_user(void *to, const void *from, unsigned long n)
410{
411 prefetch(from);
412 if (access_ok(VERIFY_WRITE, to, n))
413 return __copy_user(to, from, n);
414 return n;
415}
416
417static inline unsigned long
418__generic_copy_from_user(void *to, const void *from, unsigned long n)
419{
420 prefetchw(to);
421 if (access_ok(VERIFY_READ, from, n))
422 return __copy_user(to, from, n);
423 else
424 memset(to, 0, n);
425 return n;
426}
427
428#define copy_to_user(to, from, n) __generic_copy_to_user((to), (from), (n))
429#define copy_from_user(to, from, n) __generic_copy_from_user((to), (from), (n))
430#define __copy_to_user(to, from, n) \
431 __generic_copy_to_user_nocheck((to), (from), (n))
432#define __copy_from_user(to, from, n) \
433 __generic_copy_from_user_nocheck((to), (from), (n))
434#define __copy_to_user_inatomic __copy_to_user
435#define __copy_from_user_inatomic __copy_from_user
436
437
438
439
440
441
442
443
444
445static inline unsigned long
446__xtensa_clear_user(void *addr, unsigned long size)
447{
448 if ( ! memset(addr, 0, size) )
449 return size;
450 return 0;
451}
452
453static inline unsigned long
454clear_user(void *addr, unsigned long size)
455{
456 if (access_ok(VERIFY_WRITE, addr, size))
457 return __xtensa_clear_user(addr, size);
458 return size ? -EFAULT : 0;
459}
460
461#define __clear_user __xtensa_clear_user
462
463
464extern long __strncpy_user(char *, const char *, long);
465#define __strncpy_from_user __strncpy_user
466
467static inline long
468strncpy_from_user(char *dst, const char *src, long count)
469{
470 if (access_ok(VERIFY_READ, src, 1))
471 return __strncpy_from_user(dst, src, count);
472 return -EFAULT;
473}
474
475
476#define strlen_user(str) strnlen_user((str), TASK_SIZE - 1)
477
478
479
480
481extern long __strnlen_user(const char *, long);
482
483static inline long strnlen_user(const char *str, long len)
484{
485 unsigned long top = __kernel_ok ? ~0UL : TASK_SIZE - 1;
486
487 if ((unsigned long)str > top)
488 return 0;
489 return __strnlen_user(str, len);
490}
491
492
493struct exception_table_entry
494{
495 unsigned long insn, fixup;
496};
497
498
499
500extern unsigned long search_exception_table(unsigned long addr);
501extern void sort_exception_table(void);
502
503
504#define fixup_exception(map_reg, fixup_unit, pc) \
505({ \
506 fixup_unit; \
507})
508
509#endif
510#endif
511