|
@@ -1,10 +1,6 @@
|
|
|
#ifndef __ALPHA_UACCESS_H
|
|
|
#define __ALPHA_UACCESS_H
|
|
|
|
|
|
-#include <linux/errno.h>
|
|
|
-#include <linux/sched.h>
|
|
|
-
|
|
|
-
|
|
|
/*
|
|
|
* The fs value determines whether argument validity checking should be
|
|
|
* performed or not. If get_fs() == USER_DS, checking is performed, with
|
|
@@ -20,9 +16,6 @@
|
|
|
#define KERNEL_DS ((mm_segment_t) { 0UL })
|
|
|
#define USER_DS ((mm_segment_t) { -0x40000000000UL })
|
|
|
|
|
|
-#define VERIFY_READ 0
|
|
|
-#define VERIFY_WRITE 1
|
|
|
-
|
|
|
#define get_fs() (current_thread_info()->addr_limit)
|
|
|
#define get_ds() (KERNEL_DS)
|
|
|
#define set_fs(x) (current_thread_info()->addr_limit = (x))
|
|
@@ -39,13 +32,13 @@
|
|
|
* - AND "addr+size" doesn't have any high-bits set
|
|
|
* - OR we are in kernel mode.
|
|
|
*/
|
|
|
-#define __access_ok(addr, size, segment) \
|
|
|
- (((segment).seg & (addr | size | (addr+size))) == 0)
|
|
|
+#define __access_ok(addr, size) \
|
|
|
+ ((get_fs().seg & (addr | size | (addr+size))) == 0)
|
|
|
|
|
|
-#define access_ok(type, addr, size) \
|
|
|
-({ \
|
|
|
- __chk_user_ptr(addr); \
|
|
|
- __access_ok(((unsigned long)(addr)), (size), get_fs()); \
|
|
|
+#define access_ok(type, addr, size) \
|
|
|
+({ \
|
|
|
+ __chk_user_ptr(addr); \
|
|
|
+ __access_ok(((unsigned long)(addr)), (size)); \
|
|
|
})
|
|
|
|
|
|
/*
|
|
@@ -61,9 +54,9 @@
|
|
|
* (b) require any knowledge of processes at this stage
|
|
|
*/
|
|
|
#define put_user(x, ptr) \
|
|
|
- __put_user_check((__typeof__(*(ptr)))(x), (ptr), sizeof(*(ptr)), get_fs())
|
|
|
+ __put_user_check((__typeof__(*(ptr)))(x), (ptr), sizeof(*(ptr)))
|
|
|
#define get_user(x, ptr) \
|
|
|
- __get_user_check((x), (ptr), sizeof(*(ptr)), get_fs())
|
|
|
+ __get_user_check((x), (ptr), sizeof(*(ptr)))
|
|
|
|
|
|
/*
|
|
|
* The "__xxx" versions do not do address space checking, useful when
|
|
@@ -81,6 +74,11 @@
|
|
|
* more extensive comments with fixup_inline_exception below for
|
|
|
* more information.
|
|
|
*/
|
|
|
+#define EXC(label,cont,res,err) \
|
|
|
+ ".section __ex_table,\"a\"\n" \
|
|
|
+ " .long "#label"-.\n" \
|
|
|
+ " lda "#res","#cont"-"#label"("#err")\n" \
|
|
|
+ ".previous\n"
|
|
|
|
|
|
extern void __get_user_unknown(void);
|
|
|
|
|
@@ -100,23 +98,23 @@ extern void __get_user_unknown(void);
|
|
|
__gu_err; \
|
|
|
})
|
|
|
|
|
|
-#define __get_user_check(x, ptr, size, segment) \
|
|
|
-({ \
|
|
|
- long __gu_err = -EFAULT; \
|
|
|
- unsigned long __gu_val = 0; \
|
|
|
- const __typeof__(*(ptr)) __user *__gu_addr = (ptr); \
|
|
|
- if (__access_ok((unsigned long)__gu_addr, size, segment)) { \
|
|
|
- __gu_err = 0; \
|
|
|
- switch (size) { \
|
|
|
- case 1: __get_user_8(__gu_addr); break; \
|
|
|
- case 2: __get_user_16(__gu_addr); break; \
|
|
|
- case 4: __get_user_32(__gu_addr); break; \
|
|
|
- case 8: __get_user_64(__gu_addr); break; \
|
|
|
- default: __get_user_unknown(); break; \
|
|
|
- } \
|
|
|
- } \
|
|
|
- (x) = (__force __typeof__(*(ptr))) __gu_val; \
|
|
|
- __gu_err; \
|
|
|
+#define __get_user_check(x, ptr, size) \
|
|
|
+({ \
|
|
|
+ long __gu_err = -EFAULT; \
|
|
|
+ unsigned long __gu_val = 0; \
|
|
|
+ const __typeof__(*(ptr)) __user *__gu_addr = (ptr); \
|
|
|
+ if (__access_ok((unsigned long)__gu_addr, size)) { \
|
|
|
+ __gu_err = 0; \
|
|
|
+ switch (size) { \
|
|
|
+ case 1: __get_user_8(__gu_addr); break; \
|
|
|
+ case 2: __get_user_16(__gu_addr); break; \
|
|
|
+ case 4: __get_user_32(__gu_addr); break; \
|
|
|
+ case 8: __get_user_64(__gu_addr); break; \
|
|
|
+ default: __get_user_unknown(); break; \
|
|
|
+ } \
|
|
|
+ } \
|
|
|
+ (x) = (__force __typeof__(*(ptr))) __gu_val; \
|
|
|
+ __gu_err; \
|
|
|
})
|
|
|
|
|
|
struct __large_struct { unsigned long buf[100]; };
|
|
@@ -125,20 +123,14 @@ struct __large_struct { unsigned long buf[100]; };
|
|
|
#define __get_user_64(addr) \
|
|
|
__asm__("1: ldq %0,%2\n" \
|
|
|
"2:\n" \
|
|
|
- ".section __ex_table,\"a\"\n" \
|
|
|
- " .long 1b - .\n" \
|
|
|
- " lda %0, 2b-1b(%1)\n" \
|
|
|
- ".previous" \
|
|
|
+ EXC(1b,2b,%0,%1) \
|
|
|
: "=r"(__gu_val), "=r"(__gu_err) \
|
|
|
: "m"(__m(addr)), "1"(__gu_err))
|
|
|
|
|
|
#define __get_user_32(addr) \
|
|
|
__asm__("1: ldl %0,%2\n" \
|
|
|
"2:\n" \
|
|
|
- ".section __ex_table,\"a\"\n" \
|
|
|
- " .long 1b - .\n" \
|
|
|
- " lda %0, 2b-1b(%1)\n" \
|
|
|
- ".previous" \
|
|
|
+ EXC(1b,2b,%0,%1) \
|
|
|
: "=r"(__gu_val), "=r"(__gu_err) \
|
|
|
: "m"(__m(addr)), "1"(__gu_err))
|
|
|
|
|
@@ -148,20 +140,14 @@ struct __large_struct { unsigned long buf[100]; };
|
|
|
#define __get_user_16(addr) \
|
|
|
__asm__("1: ldwu %0,%2\n" \
|
|
|
"2:\n" \
|
|
|
- ".section __ex_table,\"a\"\n" \
|
|
|
- " .long 1b - .\n" \
|
|
|
- " lda %0, 2b-1b(%1)\n" \
|
|
|
- ".previous" \
|
|
|
+ EXC(1b,2b,%0,%1) \
|
|
|
: "=r"(__gu_val), "=r"(__gu_err) \
|
|
|
: "m"(__m(addr)), "1"(__gu_err))
|
|
|
|
|
|
#define __get_user_8(addr) \
|
|
|
__asm__("1: ldbu %0,%2\n" \
|
|
|
"2:\n" \
|
|
|
- ".section __ex_table,\"a\"\n" \
|
|
|
- " .long 1b - .\n" \
|
|
|
- " lda %0, 2b-1b(%1)\n" \
|
|
|
- ".previous" \
|
|
|
+ EXC(1b,2b,%0,%1) \
|
|
|
: "=r"(__gu_val), "=r"(__gu_err) \
|
|
|
: "m"(__m(addr)), "1"(__gu_err))
|
|
|
#else
|
|
@@ -177,12 +163,8 @@ struct __large_struct { unsigned long buf[100]; };
|
|
|
" extwh %1,%3,%1\n" \
|
|
|
" or %0,%1,%0\n" \
|
|
|
"3:\n" \
|
|
|
- ".section __ex_table,\"a\"\n" \
|
|
|
- " .long 1b - .\n" \
|
|
|
- " lda %0, 3b-1b(%2)\n" \
|
|
|
- " .long 2b - .\n" \
|
|
|
- " lda %0, 3b-2b(%2)\n" \
|
|
|
- ".previous" \
|
|
|
+ EXC(1b,3b,%0,%2) \
|
|
|
+ EXC(2b,3b,%0,%2) \
|
|
|
: "=&r"(__gu_val), "=&r"(__gu_tmp), "=r"(__gu_err) \
|
|
|
: "r"(addr), "2"(__gu_err)); \
|
|
|
}
|
|
@@ -191,10 +173,7 @@ struct __large_struct { unsigned long buf[100]; };
|
|
|
__asm__("1: ldq_u %0,0(%2)\n" \
|
|
|
" extbl %0,%2,%0\n" \
|
|
|
"2:\n" \
|
|
|
- ".section __ex_table,\"a\"\n" \
|
|
|
- " .long 1b - .\n" \
|
|
|
- " lda %0, 2b-1b(%1)\n" \
|
|
|
- ".previous" \
|
|
|
+ EXC(1b,2b,%0,%1) \
|
|
|
: "=&r"(__gu_val), "=r"(__gu_err) \
|
|
|
: "r"(addr), "1"(__gu_err))
|
|
|
#endif
|
|
@@ -215,21 +194,21 @@ extern void __put_user_unknown(void);
|
|
|
__pu_err; \
|
|
|
})
|
|
|
|
|
|
-#define __put_user_check(x, ptr, size, segment) \
|
|
|
-({ \
|
|
|
- long __pu_err = -EFAULT; \
|
|
|
- __typeof__(*(ptr)) __user *__pu_addr = (ptr); \
|
|
|
- if (__access_ok((unsigned long)__pu_addr, size, segment)) { \
|
|
|
- __pu_err = 0; \
|
|
|
- switch (size) { \
|
|
|
- case 1: __put_user_8(x, __pu_addr); break; \
|
|
|
- case 2: __put_user_16(x, __pu_addr); break; \
|
|
|
- case 4: __put_user_32(x, __pu_addr); break; \
|
|
|
- case 8: __put_user_64(x, __pu_addr); break; \
|
|
|
- default: __put_user_unknown(); break; \
|
|
|
- } \
|
|
|
- } \
|
|
|
- __pu_err; \
|
|
|
+#define __put_user_check(x, ptr, size) \
|
|
|
+({ \
|
|
|
+ long __pu_err = -EFAULT; \
|
|
|
+ __typeof__(*(ptr)) __user *__pu_addr = (ptr); \
|
|
|
+ if (__access_ok((unsigned long)__pu_addr, size)) { \
|
|
|
+ __pu_err = 0; \
|
|
|
+ switch (size) { \
|
|
|
+ case 1: __put_user_8(x, __pu_addr); break; \
|
|
|
+ case 2: __put_user_16(x, __pu_addr); break; \
|
|
|
+ case 4: __put_user_32(x, __pu_addr); break; \
|
|
|
+ case 8: __put_user_64(x, __pu_addr); break; \
|
|
|
+ default: __put_user_unknown(); break; \
|
|
|
+ } \
|
|
|
+ } \
|
|
|
+ __pu_err; \
|
|
|
})
|
|
|
|
|
|
/*
|
|
@@ -240,20 +219,14 @@ extern void __put_user_unknown(void);
|
|
|
#define __put_user_64(x, addr) \
|
|
|
__asm__ __volatile__("1: stq %r2,%1\n" \
|
|
|
"2:\n" \
|
|
|
- ".section __ex_table,\"a\"\n" \
|
|
|
- " .long 1b - .\n" \
|
|
|
- " lda $31,2b-1b(%0)\n" \
|
|
|
- ".previous" \
|
|
|
+ EXC(1b,2b,$31,%0) \
|
|
|
: "=r"(__pu_err) \
|
|
|
: "m" (__m(addr)), "rJ" (x), "0"(__pu_err))
|
|
|
|
|
|
#define __put_user_32(x, addr) \
|
|
|
__asm__ __volatile__("1: stl %r2,%1\n" \
|
|
|
"2:\n" \
|
|
|
- ".section __ex_table,\"a\"\n" \
|
|
|
- " .long 1b - .\n" \
|
|
|
- " lda $31,2b-1b(%0)\n" \
|
|
|
- ".previous" \
|
|
|
+ EXC(1b,2b,$31,%0) \
|
|
|
: "=r"(__pu_err) \
|
|
|
: "m"(__m(addr)), "rJ"(x), "0"(__pu_err))
|
|
|
|
|
@@ -263,20 +236,14 @@ __asm__ __volatile__("1: stl %r2,%1\n" \
|
|
|
#define __put_user_16(x, addr) \
|
|
|
__asm__ __volatile__("1: stw %r2,%1\n" \
|
|
|
"2:\n" \
|
|
|
- ".section __ex_table,\"a\"\n" \
|
|
|
- " .long 1b - .\n" \
|
|
|
- " lda $31,2b-1b(%0)\n" \
|
|
|
- ".previous" \
|
|
|
+ EXC(1b,2b,$31,%0) \
|
|
|
: "=r"(__pu_err) \
|
|
|
: "m"(__m(addr)), "rJ"(x), "0"(__pu_err))
|
|
|
|
|
|
#define __put_user_8(x, addr) \
|
|
|
__asm__ __volatile__("1: stb %r2,%1\n" \
|
|
|
"2:\n" \
|
|
|
- ".section __ex_table,\"a\"\n" \
|
|
|
- " .long 1b - .\n" \
|
|
|
- " lda $31,2b-1b(%0)\n" \
|
|
|
- ".previous" \
|
|
|
+ EXC(1b,2b,$31,%0) \
|
|
|
: "=r"(__pu_err) \
|
|
|
: "m"(__m(addr)), "rJ"(x), "0"(__pu_err))
|
|
|
#else
|
|
@@ -298,16 +265,10 @@ __asm__ __volatile__("1: stb %r2,%1\n" \
|
|
|
"3: stq_u %2,1(%5)\n" \
|
|
|
"4: stq_u %1,0(%5)\n" \
|
|
|
"5:\n" \
|
|
|
- ".section __ex_table,\"a\"\n" \
|
|
|
- " .long 1b - .\n" \
|
|
|
- " lda $31, 5b-1b(%0)\n" \
|
|
|
- " .long 2b - .\n" \
|
|
|
- " lda $31, 5b-2b(%0)\n" \
|
|
|
- " .long 3b - .\n" \
|
|
|
- " lda $31, 5b-3b(%0)\n" \
|
|
|
- " .long 4b - .\n" \
|
|
|
- " lda $31, 5b-4b(%0)\n" \
|
|
|
- ".previous" \
|
|
|
+ EXC(1b,5b,$31,%0) \
|
|
|
+ EXC(2b,5b,$31,%0) \
|
|
|
+ EXC(3b,5b,$31,%0) \
|
|
|
+ EXC(4b,5b,$31,%0) \
|
|
|
: "=r"(__pu_err), "=&r"(__pu_tmp1), \
|
|
|
"=&r"(__pu_tmp2), "=&r"(__pu_tmp3), \
|
|
|
"=&r"(__pu_tmp4) \
|
|
@@ -324,12 +285,8 @@ __asm__ __volatile__("1: stb %r2,%1\n" \
|
|
|
" or %1,%2,%1\n" \
|
|
|
"2: stq_u %1,0(%4)\n" \
|
|
|
"3:\n" \
|
|
|
- ".section __ex_table,\"a\"\n" \
|
|
|
- " .long 1b - .\n" \
|
|
|
- " lda $31, 3b-1b(%0)\n" \
|
|
|
- " .long 2b - .\n" \
|
|
|
- " lda $31, 3b-2b(%0)\n" \
|
|
|
- ".previous" \
|
|
|
+ EXC(1b,3b,$31,%0) \
|
|
|
+ EXC(2b,3b,$31,%0) \
|
|
|
: "=r"(__pu_err), \
|
|
|
"=&r"(__pu_tmp1), "=&r"(__pu_tmp2) \
|
|
|
: "r"((unsigned long)(x)), "r"(addr), "0"(__pu_err)); \
|
|
@@ -341,153 +298,37 @@ __asm__ __volatile__("1: stb %r2,%1\n" \
|
|
|
* Complex access routines
|
|
|
*/
|
|
|
|
|
|
-/* This little bit of silliness is to get the GP loaded for a function
|
|
|
- that ordinarily wouldn't. Otherwise we could have it done by the macro
|
|
|
- directly, which can be optimized the linker. */
|
|
|
-#ifdef MODULE
|
|
|
-#define __module_address(sym) "r"(sym),
|
|
|
-#define __module_call(ra, arg, sym) "jsr $" #ra ",(%" #arg ")," #sym
|
|
|
-#else
|
|
|
-#define __module_address(sym)
|
|
|
-#define __module_call(ra, arg, sym) "bsr $" #ra "," #sym " !samegp"
|
|
|
-#endif
|
|
|
-
|
|
|
-extern void __copy_user(void);
|
|
|
-
|
|
|
-extern inline long
|
|
|
-__copy_tofrom_user_nocheck(void *to, const void *from, long len)
|
|
|
-{
|
|
|
- register void * __cu_to __asm__("$6") = to;
|
|
|
- register const void * __cu_from __asm__("$7") = from;
|
|
|
- register long __cu_len __asm__("$0") = len;
|
|
|
-
|
|
|
- __asm__ __volatile__(
|
|
|
- __module_call(28, 3, __copy_user)
|
|
|
- : "=r" (__cu_len), "=r" (__cu_from), "=r" (__cu_to)
|
|
|
- : __module_address(__copy_user)
|
|
|
- "0" (__cu_len), "1" (__cu_from), "2" (__cu_to)
|
|
|
- : "$1", "$2", "$3", "$4", "$5", "$28", "memory");
|
|
|
-
|
|
|
- return __cu_len;
|
|
|
-}
|
|
|
-
|
|
|
-#define __copy_to_user(to, from, n) \
|
|
|
-({ \
|
|
|
- __chk_user_ptr(to); \
|
|
|
- __copy_tofrom_user_nocheck((__force void *)(to), (from), (n)); \
|
|
|
-})
|
|
|
-#define __copy_from_user(to, from, n) \
|
|
|
-({ \
|
|
|
- __chk_user_ptr(from); \
|
|
|
- __copy_tofrom_user_nocheck((to), (__force void *)(from), (n)); \
|
|
|
-})
|
|
|
-
|
|
|
-#define __copy_to_user_inatomic __copy_to_user
|
|
|
-#define __copy_from_user_inatomic __copy_from_user
|
|
|
+extern long __copy_user(void *to, const void *from, long len);
|
|
|
|
|
|
-extern inline long
|
|
|
-copy_to_user(void __user *to, const void *from, long n)
|
|
|
+static inline unsigned long
|
|
|
+raw_copy_from_user(void *to, const void __user *from, unsigned long len)
|
|
|
{
|
|
|
- if (likely(__access_ok((unsigned long)to, n, get_fs())))
|
|
|
- n = __copy_tofrom_user_nocheck((__force void *)to, from, n);
|
|
|
- return n;
|
|
|
+ return __copy_user(to, (__force const void *)from, len);
|
|
|
}
|
|
|
|
|
|
-extern inline long
|
|
|
-copy_from_user(void *to, const void __user *from, long n)
|
|
|
+static inline unsigned long
|
|
|
+raw_copy_to_user(void __user *to, const void *from, unsigned long len)
|
|
|
{
|
|
|
- long res = n;
|
|
|
- if (likely(__access_ok((unsigned long)from, n, get_fs())))
|
|
|
- res = __copy_from_user_inatomic(to, from, n);
|
|
|
- if (unlikely(res))
|
|
|
- memset(to + (n - res), 0, res);
|
|
|
- return res;
|
|
|
+ return __copy_user((__force void *)to, from, len);
|
|
|
}
|
|
|
|
|
|
-extern void __do_clear_user(void);
|
|
|
-
|
|
|
-extern inline long
|
|
|
-__clear_user(void __user *to, long len)
|
|
|
-{
|
|
|
- register void __user * __cl_to __asm__("$6") = to;
|
|
|
- register long __cl_len __asm__("$0") = len;
|
|
|
- __asm__ __volatile__(
|
|
|
- __module_call(28, 2, __do_clear_user)
|
|
|
- : "=r"(__cl_len), "=r"(__cl_to)
|
|
|
- : __module_address(__do_clear_user)
|
|
|
- "0"(__cl_len), "1"(__cl_to)
|
|
|
- : "$1", "$2", "$3", "$4", "$5", "$28", "memory");
|
|
|
- return __cl_len;
|
|
|
-}
|
|
|
+extern long __clear_user(void __user *to, long len);
|
|
|
|
|
|
extern inline long
|
|
|
clear_user(void __user *to, long len)
|
|
|
{
|
|
|
- if (__access_ok((unsigned long)to, len, get_fs()))
|
|
|
+ if (__access_ok((unsigned long)to, len))
|
|
|
len = __clear_user(to, len);
|
|
|
return len;
|
|
|
}
|
|
|
|
|
|
-#undef __module_address
|
|
|
-#undef __module_call
|
|
|
-
|
|
|
#define user_addr_max() \
|
|
|
- (segment_eq(get_fs(), USER_DS) ? TASK_SIZE : ~0UL)
|
|
|
+ (uaccess_kernel() ? ~0UL : TASK_SIZE)
|
|
|
|
|
|
extern long strncpy_from_user(char *dest, const char __user *src, long count);
|
|
|
extern __must_check long strlen_user(const char __user *str);
|
|
|
extern __must_check long strnlen_user(const char __user *str, long n);
|
|
|
|
|
|
-/*
|
|
|
- * About the exception table:
|
|
|
- *
|
|
|
- * - insn is a 32-bit pc-relative offset from the faulting insn.
|
|
|
- * - nextinsn is a 16-bit offset off of the faulting instruction
|
|
|
- * (not off of the *next* instruction as branches are).
|
|
|
- * - errreg is the register in which to place -EFAULT.
|
|
|
- * - valreg is the final target register for the load sequence
|
|
|
- * and will be zeroed.
|
|
|
- *
|
|
|
- * Either errreg or valreg may be $31, in which case nothing happens.
|
|
|
- *
|
|
|
- * The exception fixup information "just so happens" to be arranged
|
|
|
- * as in a MEM format instruction. This lets us emit our three
|
|
|
- * values like so:
|
|
|
- *
|
|
|
- * lda valreg, nextinsn(errreg)
|
|
|
- *
|
|
|
- */
|
|
|
-
|
|
|
-struct exception_table_entry
|
|
|
-{
|
|
|
- signed int insn;
|
|
|
- union exception_fixup {
|
|
|
- unsigned unit;
|
|
|
- struct {
|
|
|
- signed int nextinsn : 16;
|
|
|
- unsigned int errreg : 5;
|
|
|
- unsigned int valreg : 5;
|
|
|
- } bits;
|
|
|
- } fixup;
|
|
|
-};
|
|
|
-
|
|
|
-/* Returns the new pc */
|
|
|
-#define fixup_exception(map_reg, _fixup, pc) \
|
|
|
-({ \
|
|
|
- if ((_fixup)->fixup.bits.valreg != 31) \
|
|
|
- map_reg((_fixup)->fixup.bits.valreg) = 0; \
|
|
|
- if ((_fixup)->fixup.bits.errreg != 31) \
|
|
|
- map_reg((_fixup)->fixup.bits.errreg) = -EFAULT; \
|
|
|
- (pc) + (_fixup)->fixup.bits.nextinsn; \
|
|
|
-})
|
|
|
-
|
|
|
-#define ARCH_HAS_RELATIVE_EXTABLE
|
|
|
-
|
|
|
-#define swap_ex_entry_fixup(a, b, tmp, delta) \
|
|
|
- do { \
|
|
|
- (a)->fixup.unit = (b)->fixup.unit; \
|
|
|
- (b)->fixup.unit = (tmp).fixup.unit; \
|
|
|
- } while (0)
|
|
|
-
|
|
|
+#include <asm/extable.h>
|
|
|
|
|
|
#endif /* __ALPHA_UACCESS_H */
|