1 |
1275 |
phoenix |
#ifndef _ASM_IA64_UACCESS_H
|
2 |
|
|
#define _ASM_IA64_UACCESS_H
|
3 |
|
|
|
4 |
|
|
/*
|
5 |
|
|
* This file defines various macros to transfer memory areas across
|
6 |
|
|
* the user/kernel boundary. This needs to be done carefully because
|
7 |
|
|
* this code is executed in kernel mode and uses user-specified
|
8 |
|
|
* addresses. Thus, we need to be careful not to let the user to
|
9 |
|
|
* trick us into accessing kernel memory that would normally be
|
10 |
|
|
* inaccessible. This code is also fairly performance sensitive,
|
11 |
|
|
* so we want to spend as little time doing safety checks as
|
12 |
|
|
* possible.
|
13 |
|
|
*
|
14 |
|
|
* To make matters a bit more interesting, these macros sometimes also
|
15 |
|
|
* called from within the kernel itself, in which case the address
|
16 |
|
|
* validity check must be skipped. The get_fs() macro tells us what
|
17 |
|
|
* to do: if get_fs()==USER_DS, checking is performed, if
|
18 |
|
|
* get_fs()==KERNEL_DS, checking is bypassed.
|
19 |
|
|
*
|
20 |
|
|
* Note that even if the memory area specified by the user is in a
|
21 |
|
|
* valid address range, it is still possible that we'll get a page
|
22 |
|
|
* fault while accessing it. This is handled by filling out an
|
23 |
|
|
* exception handler fixup entry for each instruction that has the
|
24 |
|
|
* potential to fault. When such a fault occurs, the page fault
|
25 |
|
|
* handler checks to see whether the faulting instruction has a fixup
|
26 |
|
|
* associated and, if so, sets r8 to -EFAULT and clears r9 to 0 and
|
27 |
|
|
* then resumes execution at the continuation point.
|
28 |
|
|
*
|
29 |
|
|
* Based on <asm-alpha/uaccess.h>.
|
30 |
|
|
*
|
31 |
|
|
* Copyright (C) 1998, 1999, 2001, 2003 Hewlett-Packard Co
|
32 |
|
|
* David Mosberger-Tang <davidm@hpl.hp.com>
|
33 |
|
|
*/
|
34 |
|
|
|
35 |
|
|
#include <linux/errno.h>
|
36 |
|
|
#include <linux/sched.h>
|
37 |
|
|
|
38 |
|
|
#include <asm/pgtable.h>
|
39 |
|
|
|
40 |
|
|
/*
|
41 |
|
|
* For historical reasons, the following macros are grossly misnamed:
|
42 |
|
|
*/
|
43 |
|
|
#define KERNEL_DS ((mm_segment_t) { ~0UL }) /* cf. access_ok() */
|
44 |
|
|
#define USER_DS ((mm_segment_t) { TASK_SIZE-1 }) /* cf. access_ok() */
|
45 |
|
|
|
46 |
|
|
#define VERIFY_READ 0
|
47 |
|
|
#define VERIFY_WRITE 1
|
48 |
|
|
|
49 |
|
|
#define get_ds() (KERNEL_DS)
|
50 |
|
|
#define get_fs() (current->addr_limit)
|
51 |
|
|
#define set_fs(x) (current->addr_limit = (x))
|
52 |
|
|
|
53 |
|
|
#define segment_eq(a,b) ((a).seg == (b).seg)
|
54 |
|
|
|
55 |
|
|
/*
|
56 |
|
|
* When accessing user memory, we need to make sure the entire area really is in
|
57 |
|
|
* user-level space. In order to do this efficiently, we make sure that the page at
|
58 |
|
|
* address TASK_SIZE is never valid. We also need to make sure that the address doesn't
|
59 |
|
|
* point inside the virtually mapped linear page table.
|
60 |
|
|
*/
|
61 |
|
|
#define __access_ok(addr,size,segment) \
|
62 |
|
|
likely(((unsigned long) (addr)) <= (segment).seg \
|
63 |
|
|
&& ((segment).seg == KERNEL_DS.seg \
|
64 |
|
|
|| REGION_OFFSET((unsigned long) (addr)) < RGN_MAP_LIMIT))
|
65 |
|
|
#define access_ok(type,addr,size) __access_ok((addr),(size),get_fs())
|
66 |
|
|
|
67 |
|
|
static inline int
|
68 |
|
|
verify_area (int type, const void *addr, unsigned long size)
|
69 |
|
|
{
|
70 |
|
|
return access_ok(type,addr,size) ? 0 : -EFAULT;
|
71 |
|
|
}
|
72 |
|
|
|
73 |
|
|
/*
|
74 |
|
|
* These are the main single-value transfer routines. They automatically
|
75 |
|
|
* use the right size if we just have the right pointer type.
|
76 |
|
|
*
|
77 |
|
|
* Careful to not
|
78 |
|
|
* (a) re-use the arguments for side effects (sizeof/typeof is ok)
|
79 |
|
|
* (b) require any knowledge of processes at this stage
|
80 |
|
|
*/
|
81 |
|
|
#define put_user(x,ptr) __put_user_check((__typeof__(*(ptr)))(x),(ptr),sizeof(*(ptr)),get_fs())
|
82 |
|
|
#define get_user(x,ptr) __get_user_check((x),(ptr),sizeof(*(ptr)),get_fs())
|
83 |
|
|
|
84 |
|
|
/*
|
85 |
|
|
* The "__xxx" versions do not do address space checking, useful when
|
86 |
|
|
* doing multiple accesses to the same area (the programmer has to do the
|
87 |
|
|
* checks by hand with "access_ok()")
|
88 |
|
|
*/
|
89 |
|
|
#define __put_user(x,ptr) __put_user_nocheck((__typeof__(*(ptr)))(x),(ptr),sizeof(*(ptr)))
|
90 |
|
|
#define __get_user(x,ptr) __get_user_nocheck((x),(ptr),sizeof(*(ptr)))
|
91 |
|
|
|
92 |
|
|
extern void __get_user_unknown (void);
|
93 |
|
|
|
94 |
|
|
#define __get_user_nocheck(x,ptr,size) \
|
95 |
|
|
({ \
|
96 |
|
|
register long __gu_err asm ("r8") = 0; \
|
97 |
|
|
register long __gu_val asm ("r9") = 0; \
|
98 |
|
|
switch (size) { \
|
99 |
|
|
case 1: __get_user_8(ptr); break; \
|
100 |
|
|
case 2: __get_user_16(ptr); break; \
|
101 |
|
|
case 4: __get_user_32(ptr); break; \
|
102 |
|
|
case 8: __get_user_64(ptr); break; \
|
103 |
|
|
default: __get_user_unknown(); break; \
|
104 |
|
|
} \
|
105 |
|
|
(x) = (__typeof__(*(ptr))) __gu_val; \
|
106 |
|
|
__gu_err; \
|
107 |
|
|
})
|
108 |
|
|
|
109 |
|
|
#define __get_user_check(x,ptr,size,segment) \
|
110 |
|
|
({ \
|
111 |
|
|
register long __gu_err asm ("r8") = -EFAULT; \
|
112 |
|
|
register long __gu_val asm ("r9") = 0; \
|
113 |
|
|
const __typeof__(*(ptr)) *__gu_addr = (ptr); \
|
114 |
|
|
if (__access_ok((long)__gu_addr,size,segment)) { \
|
115 |
|
|
__gu_err = 0; \
|
116 |
|
|
switch (size) { \
|
117 |
|
|
case 1: __get_user_8(__gu_addr); break; \
|
118 |
|
|
case 2: __get_user_16(__gu_addr); break; \
|
119 |
|
|
case 4: __get_user_32(__gu_addr); break; \
|
120 |
|
|
case 8: __get_user_64(__gu_addr); break; \
|
121 |
|
|
default: __get_user_unknown(); break; \
|
122 |
|
|
} \
|
123 |
|
|
} \
|
124 |
|
|
(x) = (__typeof__(*(ptr))) __gu_val; \
|
125 |
|
|
__gu_err; \
|
126 |
|
|
})
|
127 |
|
|
|
128 |
|
|
struct __large_struct { unsigned long buf[100]; };
|
129 |
|
|
#define __m(x) (*(struct __large_struct *)(x))
|
130 |
|
|
|
131 |
|
|
/* We need to declare the __ex_table section before we can use it in .xdata. */
|
132 |
|
|
asm (".section \"__ex_table\", \"a\"\n\t.previous");
|
133 |
|
|
|
134 |
|
|
#if __GNUC__ >= 3
|
135 |
|
|
# define GAS_HAS_LOCAL_TAGS /* define if gas supports local tags a la [1:] */
|
136 |
|
|
#endif
|
137 |
|
|
|
138 |
|
|
#ifdef GAS_HAS_LOCAL_TAGS
|
139 |
|
|
# define _LL "[1:]"
|
140 |
|
|
#else
|
141 |
|
|
# define _LL "1:"
|
142 |
|
|
#endif
|
143 |
|
|
|
144 |
|
|
#define __get_user_64(addr) \
|
145 |
|
|
asm ("\n"_LL"\tld8 %0=%2%P2\t// %0 and %1 get overwritten by exception handler\n" \
|
146 |
|
|
"\t.xdata4 \"__ex_table\", @gprel(1b), @gprel(1f)+4\n" \
|
147 |
|
|
_LL \
|
148 |
|
|
: "=r"(__gu_val), "=r"(__gu_err) : "m"(__m(addr)), "1"(__gu_err));
|
149 |
|
|
|
150 |
|
|
#define __get_user_32(addr) \
|
151 |
|
|
asm ("\n"_LL"\tld4 %0=%2%P2\t// %0 and %1 get overwritten by exception handler\n" \
|
152 |
|
|
"\t.xdata4 \"__ex_table\", @gprel(1b), @gprel(1f)+4\n" \
|
153 |
|
|
_LL \
|
154 |
|
|
: "=r"(__gu_val), "=r"(__gu_err) : "m"(__m(addr)), "1"(__gu_err));
|
155 |
|
|
|
156 |
|
|
#define __get_user_16(addr) \
|
157 |
|
|
asm ("\n"_LL"\tld2 %0=%2%P2\t// %0 and %1 get overwritten by exception handler\n" \
|
158 |
|
|
"\t.xdata4 \"__ex_table\", @gprel(1b), @gprel(1f)+4\n" \
|
159 |
|
|
_LL \
|
160 |
|
|
: "=r"(__gu_val), "=r"(__gu_err) : "m"(__m(addr)), "1"(__gu_err));
|
161 |
|
|
|
162 |
|
|
#define __get_user_8(addr) \
|
163 |
|
|
asm ("\n"_LL"\tld1 %0=%2%P2\t// %0 and %1 get overwritten by exception handler\n" \
|
164 |
|
|
"\t.xdata4 \"__ex_table\", @gprel(1b), @gprel(1f)+4\n" \
|
165 |
|
|
_LL \
|
166 |
|
|
: "=r"(__gu_val), "=r"(__gu_err) : "m"(__m(addr)), "1"(__gu_err));
|
167 |
|
|
|
168 |
|
|
extern void __put_user_unknown (void);
|
169 |
|
|
|
170 |
|
|
#define __put_user_nocheck(x,ptr,size) \
|
171 |
|
|
({ \
|
172 |
|
|
register long __pu_err asm ("r8") = 0; \
|
173 |
|
|
switch (size) { \
|
174 |
|
|
case 1: __put_user_8(x,ptr); break; \
|
175 |
|
|
case 2: __put_user_16(x,ptr); break; \
|
176 |
|
|
case 4: __put_user_32(x,ptr); break; \
|
177 |
|
|
case 8: __put_user_64(x,ptr); break; \
|
178 |
|
|
default: __put_user_unknown(); break; \
|
179 |
|
|
} \
|
180 |
|
|
__pu_err; \
|
181 |
|
|
})
|
182 |
|
|
|
183 |
|
|
#define __put_user_check(x,ptr,size,segment) \
|
184 |
|
|
({ \
|
185 |
|
|
register long __pu_err asm ("r8") = -EFAULT; \
|
186 |
|
|
__typeof__(*(ptr)) *__pu_addr = (ptr); \
|
187 |
|
|
if (__access_ok((long)__pu_addr,size,segment)) { \
|
188 |
|
|
__pu_err = 0; \
|
189 |
|
|
switch (size) { \
|
190 |
|
|
case 1: __put_user_8(x,__pu_addr); break; \
|
191 |
|
|
case 2: __put_user_16(x,__pu_addr); break; \
|
192 |
|
|
case 4: __put_user_32(x,__pu_addr); break; \
|
193 |
|
|
case 8: __put_user_64(x,__pu_addr); break; \
|
194 |
|
|
default: __put_user_unknown(); break; \
|
195 |
|
|
} \
|
196 |
|
|
} \
|
197 |
|
|
__pu_err; \
|
198 |
|
|
})
|
199 |
|
|
|
200 |
|
|
/*
|
201 |
|
|
* The "__put_user_xx()" macros tell gcc they read from memory
|
202 |
|
|
* instead of writing: this is because they do not write to
|
203 |
|
|
* any memory gcc knows about, so there are no aliasing issues
|
204 |
|
|
*/
|
205 |
|
|
#define __put_user_64(x,addr) \
|
206 |
|
|
asm volatile ( \
|
207 |
|
|
"\n"_LL"\tst8 %1=%r2%P1\t// %0 gets overwritten by exception handler\n" \
|
208 |
|
|
"\t.xdata4 \"__ex_table\", @gprel(1b), @gprel(1f)\n" \
|
209 |
|
|
_LL \
|
210 |
|
|
: "=r"(__pu_err) : "m"(__m(addr)), "rO"(x), "0"(__pu_err))
|
211 |
|
|
|
212 |
|
|
#define __put_user_32(x,addr) \
|
213 |
|
|
asm volatile ( \
|
214 |
|
|
"\n"_LL"\tst4 %1=%r2%P1\t// %0 gets overwritten by exception handler\n" \
|
215 |
|
|
"\t.xdata4 \"__ex_table\", @gprel(1b), @gprel(1f)\n" \
|
216 |
|
|
_LL \
|
217 |
|
|
: "=r"(__pu_err) : "m"(__m(addr)), "rO"(x), "0"(__pu_err))
|
218 |
|
|
|
219 |
|
|
#define __put_user_16(x,addr) \
|
220 |
|
|
asm volatile ( \
|
221 |
|
|
"\n"_LL"\tst2 %1=%r2%P1\t// %0 gets overwritten by exception handler\n" \
|
222 |
|
|
"\t.xdata4 \"__ex_table\", @gprel(1b), @gprel(1f)\n" \
|
223 |
|
|
_LL \
|
224 |
|
|
: "=r"(__pu_err) : "m"(__m(addr)), "rO"(x), "0"(__pu_err))
|
225 |
|
|
|
226 |
|
|
#define __put_user_8(x,addr) \
|
227 |
|
|
asm volatile ( \
|
228 |
|
|
"\n"_LL"\tst1 %1=%r2%P1\t// %0 gets overwritten by exception handler\n" \
|
229 |
|
|
"\t.xdata4 \"__ex_table\", @gprel(1b), @gprel(1f)\n" \
|
230 |
|
|
_LL \
|
231 |
|
|
: "=r"(__pu_err) : "m"(__m(addr)), "rO"(x), "0"(__pu_err))
|
232 |
|
|
|
233 |
|
|
/*
|
234 |
|
|
* Complex access routines
|
235 |
|
|
*/
|
236 |
|
|
extern unsigned long __copy_user (void *to, const void *from, unsigned long count);
|
237 |
|
|
|
238 |
|
|
#define __copy_to_user(to,from,n) __copy_user((to), (from), (n))
|
239 |
|
|
#define __copy_from_user(to,from,n) __copy_user((to), (from), (n))
|
240 |
|
|
|
241 |
|
|
#define copy_to_user(to,from,n) __copy_tofrom_user((to), (from), (n), 1)
|
242 |
|
|
#define copy_from_user(to,from,n) __copy_tofrom_user((to), (from), (n), 0)
|
243 |
|
|
|
244 |
|
|
#define __copy_tofrom_user(to,from,n,check_to) \
|
245 |
|
|
({ \
|
246 |
|
|
void *__cu_to = (to); \
|
247 |
|
|
const void *__cu_from = (from); \
|
248 |
|
|
long __cu_len = (n); \
|
249 |
|
|
\
|
250 |
|
|
if (__access_ok((long) ((check_to) ? __cu_to : __cu_from), __cu_len, get_fs())) { \
|
251 |
|
|
__cu_len = __copy_user(__cu_to, __cu_from, __cu_len); \
|
252 |
|
|
} \
|
253 |
|
|
__cu_len; \
|
254 |
|
|
})
|
255 |
|
|
|
256 |
|
|
extern unsigned long __do_clear_user (void *, unsigned long);
|
257 |
|
|
|
258 |
|
|
#define __clear_user(to,n) \
|
259 |
|
|
({ \
|
260 |
|
|
__do_clear_user(to,n); \
|
261 |
|
|
})
|
262 |
|
|
|
263 |
|
|
#define clear_user(to,n) \
|
264 |
|
|
({ \
|
265 |
|
|
unsigned long __cu_len = (n); \
|
266 |
|
|
if (__access_ok((long) to, __cu_len, get_fs())) { \
|
267 |
|
|
__cu_len = __do_clear_user(to, __cu_len); \
|
268 |
|
|
} \
|
269 |
|
|
__cu_len; \
|
270 |
|
|
})
|
271 |
|
|
|
272 |
|
|
|
273 |
|
|
/* Returns: -EFAULT if exception before terminator, N if the entire
|
274 |
|
|
buffer filled, else strlen. */
|
275 |
|
|
|
276 |
|
|
extern long __strncpy_from_user (char *to, const char *from, long to_len);
|
277 |
|
|
|
278 |
|
|
#define strncpy_from_user(to,from,n) \
|
279 |
|
|
({ \
|
280 |
|
|
const char * __sfu_from = (from); \
|
281 |
|
|
long __sfu_ret = -EFAULT; \
|
282 |
|
|
if (__access_ok((long) __sfu_from, 0, get_fs())) \
|
283 |
|
|
__sfu_ret = __strncpy_from_user((to), __sfu_from, (n)); \
|
284 |
|
|
__sfu_ret; \
|
285 |
|
|
})
|
286 |
|
|
|
287 |
|
|
/* Returns: 0 if bad, string length+1 (memory size) of string if ok */
|
288 |
|
|
extern unsigned long __strlen_user (const char *);
|
289 |
|
|
|
290 |
|
|
#define strlen_user(str) \
|
291 |
|
|
({ \
|
292 |
|
|
const char *__su_str = (str); \
|
293 |
|
|
unsigned long __su_ret = 0; \
|
294 |
|
|
if (__access_ok((long) __su_str, 0, get_fs())) \
|
295 |
|
|
__su_ret = __strlen_user(__su_str); \
|
296 |
|
|
__su_ret; \
|
297 |
|
|
})
|
298 |
|
|
|
299 |
|
|
/*
|
300 |
|
|
* Returns: 0 if exception before NUL or reaching the supplied limit
|
301 |
|
|
* (N), a value greater than N if the limit would be exceeded, else
|
302 |
|
|
* strlen.
|
303 |
|
|
*/
|
304 |
|
|
extern unsigned long __strnlen_user (const char *, long);
|
305 |
|
|
|
306 |
|
|
#define strnlen_user(str, len) \
|
307 |
|
|
({ \
|
308 |
|
|
const char *__su_str = (str); \
|
309 |
|
|
unsigned long __su_ret = 0; \
|
310 |
|
|
if (__access_ok((long) __su_str, 0, get_fs())) \
|
311 |
|
|
__su_ret = __strnlen_user(__su_str, len); \
|
312 |
|
|
__su_ret; \
|
313 |
|
|
})
|
314 |
|
|
|
315 |
|
|
struct exception_table_entry {
|
316 |
|
|
int addr; /* gp-relative address of insn this fixup is for */
|
317 |
|
|
int cont; /* gp-relative continuation address; if bit 2 is set, r9 is set to 0 */
|
318 |
|
|
};
|
319 |
|
|
|
320 |
|
|
struct exception_fixup {
|
321 |
|
|
unsigned long cont; /* continuation point (bit 2: clear r9 if set) */
|
322 |
|
|
};
|
323 |
|
|
|
324 |
|
|
extern struct exception_fixup search_exception_table (unsigned long addr);
|
325 |
|
|
extern void handle_exception (struct pt_regs *regs, struct exception_fixup fixup);
|
326 |
|
|
|
327 |
|
|
#ifdef GAS_HAS_LOCAL_TAGS
|
328 |
|
|
#define SEARCH_EXCEPTION_TABLE(regs) search_exception_table(regs->cr_iip + ia64_psr(regs)->ri);
|
329 |
|
|
#else
|
330 |
|
|
#define SEARCH_EXCEPTION_TABLE(regs) search_exception_table(regs->cr_iip);
|
331 |
|
|
#endif
|
332 |
|
|
|
333 |
|
|
static inline int
|
334 |
|
|
done_with_exception (struct pt_regs *regs)
|
335 |
|
|
{
|
336 |
|
|
struct exception_fixup fix;
|
337 |
|
|
fix = SEARCH_EXCEPTION_TABLE(regs);
|
338 |
|
|
if (fix.cont) {
|
339 |
|
|
handle_exception(regs, fix);
|
340 |
|
|
return 1;
|
341 |
|
|
}
|
342 |
|
|
return 0;
|
343 |
|
|
}
|
344 |
|
|
|
345 |
|
|
#endif /* _ASM_IA64_UACCESS_H */
|