m68k: Provide __{get,put}_kernel_nofault
authorChristoph Hellwig <hch@lst.de>
Thu, 16 Sep 2021 07:04:04 +0000 (09:04 +0200)
committerGeert Uytterhoeven <geert@linux-m68k.org>
Fri, 24 Sep 2021 11:35:07 +0000 (13:35 +0200)
Allow non-faulting access to kernel addresses without overriding the
address space.  Implemented by passing the instruction name to the
low-level assembly macros as an argument, and force the use of the
normal move instructions for kernel access.

Signed-off-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Michael Schmitz <schmitzmic@gmail.com>
Tested-by: Michael Schmitz <schmitzmic@gmail.com>
Link: https://lore.kernel.org/r/20210916070405.52750-6-hch@lst.de
Signed-off-by: Geert Uytterhoeven <geert@linux-m68k.org>
arch/m68k/include/asm/uaccess.h

index 288ef7d..65581a7 100644 (file)
@@ -39,9 +39,9 @@ static inline int access_ok(const void __user *addr,
 #define        MOVES   "move"
 #endif
 
-#define __put_user_asm(res, x, ptr, bwl, reg, err)     \
+#define __put_user_asm(inst, res, x, ptr, bwl, reg, err) \
 asm volatile ("\n"                                     \
-       "1:     "MOVES"."#bwl"  %2,%1\n"                \
+       "1:     "inst"."#bwl"   %2,%1\n"                \
        "2:\n"                                          \
        "       .section .fixup,\"ax\"\n"               \
        "       .even\n"                                \
@@ -57,13 +57,13 @@ asm volatile ("\n"                                  \
        : "+d" (res), "=m" (*(ptr))                     \
        : #reg (x), "i" (err))
 
-#define __put_user_asm8(res, x, ptr)                           \
+#define __put_user_asm8(inst, res, x, ptr)                     \
 do {                                                           \
        const void *__pu_ptr = (const void __force *)(ptr);     \
                                                                \
        asm volatile ("\n"                                      \
-               "1:     "MOVES".l %2,(%1)+\n"                   \
-               "2:     "MOVES".l %R2,(%1)\n"                   \
+               "1:     "inst".l %2,(%1)+\n"                    \
+               "2:     "inst".l %R2,(%1)\n"                    \
                "3:\n"                                          \
                "       .section .fixup,\"ax\"\n"               \
                "       .even\n"                                \
@@ -94,16 +94,16 @@ do {                                                                \
        __chk_user_ptr(ptr);                                            \
        switch (sizeof (*(ptr))) {                                      \
        case 1:                                                         \
-               __put_user_asm(__pu_err, __pu_val, ptr, b, d, -EFAULT); \
+               __put_user_asm(MOVES, __pu_err, __pu_val, ptr, b, d, -EFAULT); \
                break;                                                  \
        case 2:                                                         \
-               __put_user_asm(__pu_err, __pu_val, ptr, w, r, -EFAULT); \
+               __put_user_asm(MOVES, __pu_err, __pu_val, ptr, w, r, -EFAULT); \
                break;                                                  \
        case 4:                                                         \
-               __put_user_asm(__pu_err, __pu_val, ptr, l, r, -EFAULT); \
+               __put_user_asm(MOVES, __pu_err, __pu_val, ptr, l, r, -EFAULT); \
                break;                                                  \
        case 8:                                                         \
-               __put_user_asm8(__pu_err, __pu_val, ptr);               \
+               __put_user_asm8(MOVES, __pu_err, __pu_val, ptr);        \
                break;                                                  \
        default:                                                        \
                BUILD_BUG();                                            \
@@ -113,10 +113,10 @@ do {                                                              \
 #define put_user(x, ptr)       __put_user(x, ptr)
 
 
-#define __get_user_asm(res, x, ptr, type, bwl, reg, err) ({            \
+#define __get_user_asm(inst, res, x, ptr, type, bwl, reg, err) ({      \
        type __gu_val;                                                  \
        asm volatile ("\n"                                              \
-               "1:     "MOVES"."#bwl"  %2,%1\n"                        \
+               "1:     "inst"."#bwl"   %2,%1\n"                        \
                "2:\n"                                                  \
                "       .section .fixup,\"ax\"\n"                       \
                "       .even\n"                                        \
@@ -134,7 +134,7 @@ do {                                                                \
        (x) = (__force typeof(*(ptr)))(__force unsigned long)__gu_val;  \
 })
 
-#define __get_user_asm8(res, x, ptr)                                   \
+#define __get_user_asm8(inst, res, x, ptr)                             \
 do {                                                                   \
        const void *__gu_ptr = (const void __force *)(ptr);             \
        union {                                                         \
@@ -143,8 +143,8 @@ do {                                                                        \
        } __gu_val;                                                     \
                                                                        \
        asm volatile ("\n"                                              \
-               "1:     "MOVES".l       (%2)+,%1\n"                     \
-               "2:     "MOVES".l       (%2),%R1\n"                     \
+               "1:     "inst".l (%2)+,%1\n"                            \
+               "2:     "inst".l (%2),%R1\n"                            \
                "3:\n"                                                  \
                "       .section .fixup,\"ax\"\n"                       \
                "       .even\n"                                        \
@@ -172,16 +172,16 @@ do {                                                                      \
        __chk_user_ptr(ptr);                                            \
        switch (sizeof(*(ptr))) {                                       \
        case 1:                                                         \
-               __get_user_asm(__gu_err, x, ptr, u8, b, d, -EFAULT);    \
+               __get_user_asm(MOVES, __gu_err, x, ptr, u8, b, d, -EFAULT); \
                break;                                                  \
        case 2:                                                         \
-               __get_user_asm(__gu_err, x, ptr, u16, w, r, -EFAULT);   \
+               __get_user_asm(MOVES, __gu_err, x, ptr, u16, w, r, -EFAULT); \
                break;                                                  \
        case 4:                                                         \
-               __get_user_asm(__gu_err, x, ptr, u32, l, r, -EFAULT);   \
+               __get_user_asm(MOVES, __gu_err, x, ptr, u32, l, r, -EFAULT); \
                break;                                                  \
        case 8:                                                         \
-               __get_user_asm8(__gu_err, x, ptr);                      \
+               __get_user_asm8(MOVES, __gu_err, x, ptr);               \
                break;                                                  \
        default:                                                        \
                BUILD_BUG();                                            \
@@ -330,16 +330,19 @@ __constant_copy_to_user(void __user *to, const void *from, unsigned long n)
 
        switch (n) {
        case 1:
-               __put_user_asm(res, *(u8 *)from, (u8 __user *)to, b, d, 1);
+               __put_user_asm(MOVES, res, *(u8 *)from, (u8 __user *)to,
+                               b, d, 1);
                break;
        case 2:
-               __put_user_asm(res, *(u16 *)from, (u16 __user *)to, w, r, 2);
+               __put_user_asm(MOVES, res, *(u16 *)from, (u16 __user *)to,
+                               w, r, 2);
                break;
        case 3:
                __constant_copy_to_user_asm(res, to, from, tmp, 3, w, b,);
                break;
        case 4:
-               __put_user_asm(res, *(u32 *)from, (u32 __user *)to, l, r, 4);
+               __put_user_asm(MOVES, res, *(u32 *)from, (u32 __user *)to,
+                               l, r, 4);
                break;
        case 5:
                __constant_copy_to_user_asm(res, to, from, tmp, 5, l, b,);
@@ -388,6 +391,66 @@ raw_copy_to_user(void __user *to, const void *from, unsigned long n)
 #define INLINE_COPY_FROM_USER
 #define INLINE_COPY_TO_USER
 
+#define HAVE_GET_KERNEL_NOFAULT
+
+#define __get_kernel_nofault(dst, src, type, err_label)                        \
+do {                                                                   \
+       type *__gk_dst = (type *)(dst);                                 \
+       type *__gk_src = (type *)(src);                                 \
+       int __gk_err = 0;                                               \
+                                                                       \
+       switch (sizeof(type)) {                                         \
+       case 1:                                                         \
+               __get_user_asm("move", __gk_err, *__gk_dst, __gk_src,   \
+                               u8, b, d, -EFAULT);                     \
+               break;                                                  \
+       case 2:                                                         \
+               __get_user_asm("move", __gk_err, *__gk_dst, __gk_src,   \
+                               u16, w, r, -EFAULT);                    \
+               break;                                                  \
+       case 4:                                                         \
+               __get_user_asm("move", __gk_err, *__gk_dst, __gk_src,   \
+                               u32, l, r, -EFAULT);                    \
+               break;                                                  \
+       case 8:                                                         \
+               __get_user_asm8("move", __gk_err, *__gk_dst, __gk_src); \
+               break;                                                  \
+       default:                                                        \
+               BUILD_BUG();                                            \
+       }                                                               \
+       if (unlikely(__gk_err))                                         \
+               goto err_label;                                         \
+} while (0)
+
+#define __put_kernel_nofault(dst, src, type, err_label)                        \
+do {                                                                   \
+       type __pk_src = *(type *)(src);                                 \
+       type *__pk_dst = (type *)(dst);                                 \
+       int __pk_err = 0;                                               \
+                                                                       \
+       switch (sizeof(type)) {                                         \
+       case 1:                                                         \
+               __put_user_asm("move", __pk_err, __pk_src, __pk_dst,    \
+                               b, d, -EFAULT);                         \
+               break;                                                  \
+       case 2:                                                         \
+               __put_user_asm("move", __pk_err, __pk_src, __pk_dst,    \
+                               w, r, -EFAULT);                         \
+               break;                                                  \
+       case 4:                                                         \
+               __put_user_asm("move", __pk_err, __pk_src, __pk_dst,    \
+                               l, r, -EFAULT);                         \
+               break;                                                  \
+       case 8:                                                         \
+               __put_user_asm8("move", __pk_err, __pk_src, __pk_dst);  \
+               break;                                                  \
+       default:                                                        \
+               BUILD_BUG();                                            \
+       }                                                               \
+       if (unlikely(__pk_err))                                         \
+               goto err_label;                                         \
+} while (0)
+
 #define user_addr_max() \
        (uaccess_kernel() ? ~0UL : TASK_SIZE)