linux/arch/m68k/include/asm/uaccess_mm.h
<<
>>
Prefs
   1#ifndef __M68K_UACCESS_H
   2#define __M68K_UACCESS_H
   3
   4/*
   5 * User space memory access functions
   6 */
   7#include <linux/compiler.h>
   8#include <linux/errno.h>
   9#include <linux/types.h>
  10#include <linux/sched.h>
  11#include <asm/segment.h>
  12
  13#define VERIFY_READ     0
  14#define VERIFY_WRITE    1
  15
  16/* We let the MMU do all checking */
  17static inline int access_ok(int type, const void __user *addr,
  18                            unsigned long size)
  19{
  20        return 1;
  21}
  22
  23/*
  24 * Not all varients of the 68k family support the notion of address spaces.
  25 * The traditional 680x0 parts do, and they use the sfc/dfc registers and
  26 * the "moves" instruction to access user space from kernel space. Other
  27 * family members like ColdFire don't support this, and only have a single
  28 * address space, and use the usual "move" instruction for user space access.
  29 *
  30 * Outside of this difference the user space access functions are the same.
  31 * So lets keep the code simple and just define in what we need to use.
  32 */
  33#ifdef CONFIG_CPU_HAS_ADDRESS_SPACES
  34#define MOVES   "moves"
  35#else
  36#define MOVES   "move"
  37#endif
  38
  39/*
  40 * The exception table consists of pairs of addresses: the first is the
  41 * address of an instruction that is allowed to fault, and the second is
  42 * the address at which the program should continue.  No registers are
  43 * modified, so it is entirely up to the continuation code to figure out
  44 * what to do.
  45 *
  46 * All the routines below use bits of fixup code that are out of line
  47 * with the main instruction path.  This means when everything is well,
  48 * we don't even have to jump over them.  Further, they do not intrude
  49 * on our cache or tlb entries.
  50 */
  51
  52struct exception_table_entry
  53{
  54        unsigned long insn, fixup;
  55};
  56
  57extern int __put_user_bad(void);
  58extern int __get_user_bad(void);
  59
  60#define __put_user_asm(res, x, ptr, bwl, reg, err)      \
  61asm volatile ("\n"                                      \
  62        "1:     "MOVES"."#bwl"  %2,%1\n"                \
  63        "2:\n"                                          \
  64        "       .section .fixup,\"ax\"\n"               \
  65        "       .even\n"                                \
  66        "10:    moveq.l %3,%0\n"                        \
  67        "       jra 2b\n"                               \
  68        "       .previous\n"                            \
  69        "\n"                                            \
  70        "       .section __ex_table,\"a\"\n"            \
  71        "       .align  4\n"                            \
  72        "       .long   1b,10b\n"                       \
  73        "       .long   2b,10b\n"                       \
  74        "       .previous"                              \
  75        : "+d" (res), "=m" (*(ptr))                     \
  76        : #reg (x), "i" (err))
  77
  78/*
  79 * These are the main single-value transfer routines.  They automatically
  80 * use the right size if we just have the right pointer type.
  81 */
  82
  83#define __put_user(x, ptr)                                              \
  84({                                                                      \
  85        typeof(*(ptr)) __pu_val = (x);                                  \
  86        int __pu_err = 0;                                               \
  87        __chk_user_ptr(ptr);                                            \
  88        switch (sizeof (*(ptr))) {                                      \
  89        case 1:                                                         \
  90                __put_user_asm(__pu_err, __pu_val, ptr, b, d, -EFAULT); \
  91                break;                                                  \
  92        case 2:                                                         \
  93                __put_user_asm(__pu_err, __pu_val, ptr, w, r, -EFAULT); \
  94                break;                                                  \
  95        case 4:                                                         \
  96                __put_user_asm(__pu_err, __pu_val, ptr, l, r, -EFAULT); \
  97                break;                                                  \
  98        case 8:                                                         \
  99            {                                                           \
 100                const void __user *__pu_ptr = (ptr);                    \
 101                asm volatile ("\n"                                      \
 102                        "1:     "MOVES".l       %2,(%1)+\n"             \
 103                        "2:     "MOVES".l       %R2,(%1)\n"             \
 104                        "3:\n"                                          \
 105                        "       .section .fixup,\"ax\"\n"               \
 106                        "       .even\n"                                \
 107                        "10:    movel %3,%0\n"                          \
 108                        "       jra 3b\n"                               \
 109                        "       .previous\n"                            \
 110                        "\n"                                            \
 111                        "       .section __ex_table,\"a\"\n"            \
 112                        "       .align 4\n"                             \
 113                        "       .long 1b,10b\n"                         \
 114                        "       .long 2b,10b\n"                         \
 115                        "       .long 3b,10b\n"                         \
 116                        "       .previous"                              \
 117                        : "+d" (__pu_err), "+a" (__pu_ptr)              \
 118                        : "r" (__pu_val), "i" (-EFAULT)                 \
 119                        : "memory");                                    \
 120                break;                                                  \
 121            }                                                           \
 122        default:                                                        \
 123                __pu_err = __put_user_bad();                            \
 124                break;                                                  \
 125        }                                                               \
 126        __pu_err;                                                       \
 127})
 128#define put_user(x, ptr)        __put_user(x, ptr)
 129
 130
 131#define __get_user_asm(res, x, ptr, type, bwl, reg, err) ({             \
 132        type __gu_val;                                                  \
 133        asm volatile ("\n"                                              \
 134                "1:     "MOVES"."#bwl"  %2,%1\n"                        \
 135                "2:\n"                                                  \
 136                "       .section .fixup,\"ax\"\n"                       \
 137                "       .even\n"                                        \
 138                "10:    move.l  %3,%0\n"                                \
 139                "       sub.l   %1,%1\n"                                \
 140                "       jra     2b\n"                                   \
 141                "       .previous\n"                                    \
 142                "\n"                                                    \
 143                "       .section __ex_table,\"a\"\n"                    \
 144                "       .align  4\n"                                    \
 145                "       .long   1b,10b\n"                               \
 146                "       .previous"                                      \
 147                : "+d" (res), "=&" #reg (__gu_val)                      \
 148                : "m" (*(ptr)), "i" (err));                             \
 149        (x) = (__force typeof(*(ptr)))(__force unsigned long)__gu_val;  \
 150})
 151
 152#define __get_user(x, ptr)                                              \
 153({                                                                      \
 154        int __gu_err = 0;                                               \
 155        __chk_user_ptr(ptr);                                            \
 156        switch (sizeof(*(ptr))) {                                       \
 157        case 1:                                                         \
 158                __get_user_asm(__gu_err, x, ptr, u8, b, d, -EFAULT);    \
 159                break;                                                  \
 160        case 2:                                                         \
 161                __get_user_asm(__gu_err, x, ptr, u16, w, r, -EFAULT);   \
 162                break;                                                  \
 163        case 4:                                                         \
 164                __get_user_asm(__gu_err, x, ptr, u32, l, r, -EFAULT);   \
 165                break;                                                  \
 166/*      case 8: disabled because gcc-4.1 has a broken typeof            \
 167            {                                                           \
 168                const void *__gu_ptr = (ptr);                           \
 169                u64 __gu_val;                                           \
 170                asm volatile ("\n"                                      \
 171                        "1:     "MOVES".l       (%2)+,%1\n"             \
 172                        "2:     "MOVES".l       (%2),%R1\n"             \
 173                        "3:\n"                                          \
 174                        "       .section .fixup,\"ax\"\n"               \
 175                        "       .even\n"                                \
 176                        "10:    move.l  %3,%0\n"                        \
 177                        "       sub.l   %1,%1\n"                        \
 178                        "       sub.l   %R1,%R1\n"                      \
 179                        "       jra     3b\n"                           \
 180                        "       .previous\n"                            \
 181                        "\n"                                            \
 182                        "       .section __ex_table,\"a\"\n"            \
 183                        "       .align  4\n"                            \
 184                        "       .long   1b,10b\n"                       \
 185                        "       .long   2b,10b\n"                       \
 186                        "       .previous"                              \
 187                        : "+d" (__gu_err), "=&r" (__gu_val),            \
 188                          "+a" (__gu_ptr)                               \
 189                        : "i" (-EFAULT)                                 \
 190                        : "memory");                                    \
 191                (x) = (__force typeof(*(ptr)))__gu_val;                 \
 192                break;                                                  \
 193            }   */                                                      \
 194        default:                                                        \
 195                __gu_err = __get_user_bad();                            \
 196                break;                                                  \
 197        }                                                               \
 198        __gu_err;                                                       \
 199})
 200#define get_user(x, ptr) __get_user(x, ptr)
 201
 202unsigned long __generic_copy_from_user(void *to, const void __user *from, unsigned long n);
 203unsigned long __generic_copy_to_user(void __user *to, const void *from, unsigned long n);
 204
 205#define __constant_copy_from_user_asm(res, to, from, tmp, n, s1, s2, s3)\
 206        asm volatile ("\n"                                              \
 207                "1:     "MOVES"."#s1"   (%2)+,%3\n"                     \
 208                "       move."#s1"      %3,(%1)+\n"                     \
 209                "2:     "MOVES"."#s2"   (%2)+,%3\n"                     \
 210                "       move."#s2"      %3,(%1)+\n"                     \
 211                "       .ifnc   \""#s3"\",\"\"\n"                       \
 212                "3:     "MOVES"."#s3"   (%2)+,%3\n"                     \
 213                "       move."#s3"      %3,(%1)+\n"                     \
 214                "       .endif\n"                                       \
 215                "4:\n"                                                  \
 216                "       .section __ex_table,\"a\"\n"                    \
 217                "       .align  4\n"                                    \
 218                "       .long   1b,10f\n"                               \
 219                "       .long   2b,20f\n"                               \
 220                "       .ifnc   \""#s3"\",\"\"\n"                       \
 221                "       .long   3b,30f\n"                               \
 222                "       .endif\n"                                       \
 223                "       .previous\n"                                    \
 224                "\n"                                                    \
 225                "       .section .fixup,\"ax\"\n"                       \
 226                "       .even\n"                                        \
 227                "10:    clr."#s1"       (%1)+\n"                        \
 228                "20:    clr."#s2"       (%1)+\n"                        \
 229                "       .ifnc   \""#s3"\",\"\"\n"                       \
 230                "30:    clr."#s3"       (%1)+\n"                        \
 231                "       .endif\n"                                       \
 232                "       moveq.l #"#n",%0\n"                             \
 233                "       jra     4b\n"                                   \
 234                "       .previous\n"                                    \
 235                : "+d" (res), "+&a" (to), "+a" (from), "=&d" (tmp)      \
 236                : : "memory")
 237
 238static __always_inline unsigned long
 239__constant_copy_from_user(void *to, const void __user *from, unsigned long n)
 240{
 241        unsigned long res = 0, tmp;
 242
 243        switch (n) {
 244        case 1:
 245                __get_user_asm(res, *(u8 *)to, (u8 __user *)from, u8, b, d, 1);
 246                break;
 247        case 2:
 248                __get_user_asm(res, *(u16 *)to, (u16 __user *)from, u16, w, r, 2);
 249                break;
 250        case 3:
 251                __constant_copy_from_user_asm(res, to, from, tmp, 3, w, b,);
 252                break;
 253        case 4:
 254                __get_user_asm(res, *(u32 *)to, (u32 __user *)from, u32, l, r, 4);
 255                break;
 256        case 5:
 257                __constant_copy_from_user_asm(res, to, from, tmp, 5, l, b,);
 258                break;
 259        case 6:
 260                __constant_copy_from_user_asm(res, to, from, tmp, 6, l, w,);
 261                break;
 262        case 7:
 263                __constant_copy_from_user_asm(res, to, from, tmp, 7, l, w, b);
 264                break;
 265        case 8:
 266                __constant_copy_from_user_asm(res, to, from, tmp, 8, l, l,);
 267                break;
 268        case 9:
 269                __constant_copy_from_user_asm(res, to, from, tmp, 9, l, l, b);
 270                break;
 271        case 10:
 272                __constant_copy_from_user_asm(res, to, from, tmp, 10, l, l, w);
 273                break;
 274        case 12:
 275                __constant_copy_from_user_asm(res, to, from, tmp, 12, l, l, l);
 276                break;
 277        default:
 278                /* we limit the inlined version to 3 moves */
 279                return __generic_copy_from_user(to, from, n);
 280        }
 281
 282        return res;
 283}
 284
 285#define __constant_copy_to_user_asm(res, to, from, tmp, n, s1, s2, s3)  \
 286        asm volatile ("\n"                                              \
 287                "       move."#s1"      (%2)+,%3\n"                     \
 288                "11:    "MOVES"."#s1"   %3,(%1)+\n"                     \
 289                "12:    move."#s2"      (%2)+,%3\n"                     \
 290                "21:    "MOVES"."#s2"   %3,(%1)+\n"                     \
 291                "22:\n"                                                 \
 292                "       .ifnc   \""#s3"\",\"\"\n"                       \
 293                "       move."#s3"      (%2)+,%3\n"                     \
 294                "31:    "MOVES"."#s3"   %3,(%1)+\n"                     \
 295                "32:\n"                                                 \
 296                "       .endif\n"                                       \
 297                "4:\n"                                                  \
 298                "\n"                                                    \
 299                "       .section __ex_table,\"a\"\n"                    \
 300                "       .align  4\n"                                    \
 301                "       .long   11b,5f\n"                               \
 302                "       .long   12b,5f\n"                               \
 303                "       .long   21b,5f\n"                               \
 304                "       .long   22b,5f\n"                               \
 305                "       .ifnc   \""#s3"\",\"\"\n"                       \
 306                "       .long   31b,5f\n"                               \
 307                "       .long   32b,5f\n"                               \
 308                "       .endif\n"                                       \
 309                "       .previous\n"                                    \
 310                "\n"                                                    \
 311                "       .section .fixup,\"ax\"\n"                       \
 312                "       .even\n"                                        \
 313                "5:     moveq.l #"#n",%0\n"                             \
 314                "       jra     4b\n"                                   \
 315                "       .previous\n"                                    \
 316                : "+d" (res), "+a" (to), "+a" (from), "=&d" (tmp)       \
 317                : : "memory")
 318
 319static __always_inline unsigned long
 320__constant_copy_to_user(void __user *to, const void *from, unsigned long n)
 321{
 322        unsigned long res = 0, tmp;
 323
 324        switch (n) {
 325        case 1:
 326                __put_user_asm(res, *(u8 *)from, (u8 __user *)to, b, d, 1);
 327                break;
 328        case 2:
 329                __put_user_asm(res, *(u16 *)from, (u16 __user *)to, w, r, 2);
 330                break;
 331        case 3:
 332                __constant_copy_to_user_asm(res, to, from, tmp, 3, w, b,);
 333                break;
 334        case 4:
 335                __put_user_asm(res, *(u32 *)from, (u32 __user *)to, l, r, 4);
 336                break;
 337        case 5:
 338                __constant_copy_to_user_asm(res, to, from, tmp, 5, l, b,);
 339                break;
 340        case 6:
 341                __constant_copy_to_user_asm(res, to, from, tmp, 6, l, w,);
 342                break;
 343        case 7:
 344                __constant_copy_to_user_asm(res, to, from, tmp, 7, l, w, b);
 345                break;
 346        case 8:
 347                __constant_copy_to_user_asm(res, to, from, tmp, 8, l, l,);
 348                break;
 349        case 9:
 350                __constant_copy_to_user_asm(res, to, from, tmp, 9, l, l, b);
 351                break;
 352        case 10:
 353                __constant_copy_to_user_asm(res, to, from, tmp, 10, l, l, w);
 354                break;
 355        case 12:
 356                __constant_copy_to_user_asm(res, to, from, tmp, 12, l, l, l);
 357                break;
 358        default:
 359                /* limit the inlined version to 3 moves */
 360                return __generic_copy_to_user(to, from, n);
 361        }
 362
 363        return res;
 364}
 365
 366#define __copy_from_user(to, from, n)           \
 367(__builtin_constant_p(n) ?                      \
 368 __constant_copy_from_user(to, from, n) :       \
 369 __generic_copy_from_user(to, from, n))
 370
 371#define __copy_to_user(to, from, n)             \
 372(__builtin_constant_p(n) ?                      \
 373 __constant_copy_to_user(to, from, n) :         \
 374 __generic_copy_to_user(to, from, n))
 375
 376#define __copy_to_user_inatomic         __copy_to_user
 377#define __copy_from_user_inatomic       __copy_from_user
 378
 379#define copy_from_user(to, from, n)     __copy_from_user(to, from, n)
 380#define copy_to_user(to, from, n)       __copy_to_user(to, from, n)
 381
 382#define user_addr_max() \
 383        (segment_eq(get_fs(), USER_DS) ? TASK_SIZE : ~0UL)
 384
 385extern long strncpy_from_user(char *dst, const char __user *src, long count);
 386extern __must_check long strlen_user(const char __user *str);
 387extern __must_check long strnlen_user(const char __user *str, long n);
 388
 389unsigned long __clear_user(void __user *to, unsigned long n);
 390
 391#define clear_user      __clear_user
 392
 393#endif /* _M68K_UACCESS_H */
 394