metag/usercopy: Add 64-bit get_user support
authorJames Hogan <james.hogan@imgtec.com>
Fri, 31 Mar 2017 14:40:52 +0000 (15:40 +0100)
committerJames Hogan <james.hogan@imgtec.com>
Wed, 5 Apr 2017 14:27:32 +0000 (15:27 +0100)
Metag already supports 64-bit put_user, so add support for 64-bit
get_user too so that the test_user_copy module can test both.

Signed-off-by: James Hogan <james.hogan@imgtec.com>
Cc: linux-metag@vger.kernel.org
arch/metag/include/asm/uaccess.h
arch/metag/lib/usercopy.c

index 07238b3..469a2f1 100644 (file)
@@ -138,7 +138,8 @@ extern long __get_user_bad(void);
 
 #define __get_user_nocheck(x, ptr, size)                       \
 ({                                                              \
-       long __gu_err, __gu_val;                                \
+       long __gu_err;                                          \
+       long long __gu_val;                                     \
        __get_user_size(__gu_val, (ptr), (size), __gu_err);     \
        (x) = (__force __typeof__(*(ptr)))__gu_val;             \
        __gu_err;                                               \
@@ -146,7 +147,8 @@ extern long __get_user_bad(void);
 
 #define __get_user_check(x, ptr, size)                                 \
 ({                                                                      \
-       long __gu_err = -EFAULT, __gu_val = 0;                          \
+       long __gu_err = -EFAULT;                                        \
+       long long __gu_val = 0;                                         \
        const __typeof__(*(ptr)) __user *__gu_addr = (ptr);             \
        if (access_ok(VERIFY_READ, __gu_addr, size))                    \
                __get_user_size(__gu_val, __gu_addr, (size), __gu_err); \
@@ -157,6 +159,7 @@ extern long __get_user_bad(void);
 extern unsigned char __get_user_asm_b(const void __user *addr, long *err);
 extern unsigned short __get_user_asm_w(const void __user *addr, long *err);
 extern unsigned int __get_user_asm_d(const void __user *addr, long *err);
+extern unsigned long long __get_user_asm_l(const void __user *addr, long *err);
 
 #define __get_user_size(x, ptr, size, retval)                  \
 do {                                                            \
@@ -168,6 +171,8 @@ do {                                                            \
                x = __get_user_asm_w(ptr, &retval); break;      \
        case 4:                                                 \
                x = __get_user_asm_d(ptr, &retval); break;      \
+       case 8:                                                 \
+               x = __get_user_asm_l(ptr, &retval); break;      \
        default:                                                \
                (x) = __get_user_bad();                         \
        }                                                       \
index ceb4590..45e7b79 100644 (file)
@@ -1044,6 +1044,30 @@ unsigned int __get_user_asm_d(const void __user *addr, long *err)
 }
 EXPORT_SYMBOL(__get_user_asm_d);
 
+unsigned long long __get_user_asm_l(const void __user *addr, long *err)
+{
+       register unsigned long long x asm ("D0Re0") = 0;
+       asm volatile (
+               "       GETL %0,%t0,[%2]\n"
+               "1:\n"
+               "       GETL %0,%t0,[%2]\n"
+               "2:\n"
+               "       .section .fixup,\"ax\"\n"
+               "3:     MOV     D0FrT,%3\n"
+               "       SETD    [%1],D0FrT\n"
+               "       MOVT    D0FrT,#HI(2b)\n"
+               "       JUMP    D0FrT,#LO(2b)\n"
+               "       .previous\n"
+               "       .section __ex_table,\"a\"\n"
+               "       .long 1b,3b\n"
+               "       .previous\n"
+               : "=r" (x)
+               : "r" (err), "r" (addr), "P" (-EFAULT)
+               : "D0FrT");
+       return x;
+}
+EXPORT_SYMBOL(__get_user_asm_l);
+
 long __put_user_asm_b(unsigned int x, void __user *addr)
 {
        register unsigned int err asm ("D0Re0") = 0;