linux/include/asm-sh/uaccess.h
<<
>>
Prefs
   1/* $Id: uaccess.h,v 1.11 2003/10/13 07:21:20 lethal Exp $
   2 *
   3 * User space memory access functions
   4 *
   5 * Copyright (C) 1999, 2002  Niibe Yutaka
   6 * Copyright (C) 2003  Paul Mundt
   7 *
   8 *  Based on:
   9 *     MIPS implementation version 1.15 by
  10 *              Copyright (C) 1996, 1997, 1998 by Ralf Baechle
  11 *     and i386 version.
  12 */
  13#ifndef __ASM_SH_UACCESS_H
  14#define __ASM_SH_UACCESS_H
  15
  16#include <linux/errno.h>
  17#include <linux/sched.h>
  18
  19/*
  20 * NOTE: Macro/functions in this file depends on threads_info.h implementation.
  21 * Assumes:
  22 * TI_FLAGS == 8
  23 * TIF_USERSPACE == 31
  24 * USER_ADDR_LIMIT == 0x80000000
  25 */
  26
  27#define VERIFY_READ    0
  28#define VERIFY_WRITE   1
  29
  30typedef struct {
  31        unsigned int is_user_space;
  32} mm_segment_t;
  33
  34/*
  35 * The fs value determines whether argument validity checking should be
  36 * performed or not.  If get_fs() == USER_DS, checking is performed, with
  37 * get_fs() == KERNEL_DS, checking is bypassed.
  38 *
  39 * For historical reasons (Data Segment Register?), these macros are misnamed.
  40 */
  41
  42#define MAKE_MM_SEG(s)  ((mm_segment_t) { (s) })
  43#define segment_eq(a,b) ((a).is_user_space == (b).is_user_space)
  44
  45#define USER_ADDR_LIMIT 0x80000000
  46
  47#define KERNEL_DS       MAKE_MM_SEG(0)
  48#define USER_DS         MAKE_MM_SEG(1)
  49
  50#define get_ds()        (KERNEL_DS)
  51
  52#if !defined(CONFIG_MMU)
  53static inline mm_segment_t get_fs(void)
  54{
  55        return USER_DS;
  56}
  57
  58static inline void set_fs(mm_segment_t s)
  59{
  60}
  61
  62/*
  63 * __access_ok: Check if address with size is OK or not.
  64 *
  65 * If we don't have an MMU (or if its disabled) the only thing we really have
  66 * to look out for is if the address resides somewhere outside of what
  67 * available RAM we have.
  68 *
  69 * TODO: This check could probably also stand to be restricted somewhat more..
  70 * though it still does the Right Thing(tm) for the time being.
  71 */
  72static inline int __access_ok(unsigned long addr, unsigned long size)
  73{
  74        extern unsigned long memory_start, memory_end;
  75
  76        return ((addr >= memory_start) && ((addr + size) < memory_end));
  77}
  78#else /* CONFIG_MMU */
  79static inline mm_segment_t get_fs(void)
  80{
  81        return MAKE_MM_SEG(test_thread_flag(TIF_USERSPACE));
  82}
  83
  84static inline void set_fs(mm_segment_t s)
  85{
  86        unsigned long ti, flag;
  87        __asm__ __volatile__(
  88                "stc    r7_bank, %0\n\t"
  89                "mov.l  @(8,%0), %1\n\t"
  90                "shal   %1\n\t"
  91                "cmp/pl %2\n\t"
  92                "rotcr  %1\n\t"
  93                "mov.l  %1, @(8,%0)"
  94                : "=&r" (ti), "=&r" (flag)
  95                : "r" (s.is_user_space)
  96                : "t");
  97/****
  98        if (s.is_user_space)
  99                set_thread_flag(TIF_USERSPACE);
 100        else
 101                clear_thread_flag(TIF_USERSPACE);
 102****/
 103}
 104
 105/*
 106 * __access_ok: Check if address with size is OK or not.
 107 *
 108 * We do three checks:
 109 * (1) is it user space? 
 110 * (2) addr + size --> carry?
 111 * (3) addr + size >= 0x80000000  (USER_ADDR_LIMIT)
 112 *
 113 * (1) (2) (3) | RESULT
 114 *  0   0   0  |  ok
 115 *  0   0   1  |  ok
 116 *  0   1   0  |  bad
 117 *  0   1   1  |  bad
 118 *  1   0   0  |  ok
 119 *  1   0   1  |  bad
 120 *  1   1   0  |  bad
 121 *  1   1   1  |  bad
 122 */
 123static inline int __access_ok(unsigned long addr, unsigned long size)
 124{
 125        unsigned long flag, tmp;
 126
 127        __asm__("stc    r7_bank, %0\n\t"
 128                "mov.l  @(8,%0), %0\n\t"
 129                "clrt\n\t"
 130                "addc   %2, %1\n\t"
 131                "and    %1, %0\n\t"
 132                "rotcl  %0\n\t"
 133                "rotcl  %0\n\t"
 134                "and    #3, %0"
 135                : "=&z" (flag), "=r" (tmp)
 136                : "r" (addr), "1" (size)
 137                : "t");
 138
 139        return flag == 0;
 140}
 141#endif /* CONFIG_MMU */
 142
 143static inline int access_ok(int type, const void __user *p, unsigned long size)
 144{
 145        unsigned long addr = (unsigned long)p;
 146        return __access_ok(addr, size);
 147}
 148
 149static inline int verify_area(int type, const void __user * addr, unsigned long size)
 150{
 151        return access_ok(type,addr,size) ? 0 : -EFAULT;
 152}
 153
 154/*
 155 * Uh, these should become the main single-value transfer routines ...
 156 * They automatically use the right size if we just have the right
 157 * pointer type ...
 158 *
 159 * As SuperH uses the same address space for kernel and user data, we
 160 * can just do these as direct assignments.
 161 *
 162 * Careful to not
 163 * (a) re-use the arguments for side effects (sizeof is ok)
 164 * (b) require any knowledge of processes at this stage
 165 */
 166#define put_user(x,ptr) __put_user_check((x),(ptr),sizeof(*(ptr)))
 167#define get_user(x,ptr) __get_user_check((x),(ptr),sizeof(*(ptr)))
 168
 169/*
 170 * The "__xxx" versions do not do address space checking, useful when
 171 * doing multiple accesses to the same area (the user has to do the
 172 * checks by hand with "access_ok()")
 173 */
 174#define __put_user(x,ptr) \
 175  __put_user_nocheck((__typeof__(*(ptr)))(x),(ptr),sizeof(*(ptr)))
 176#define __get_user(x,ptr) \
 177  __get_user_nocheck((x),(ptr),sizeof(*(ptr)))
 178
 179struct __large_struct { unsigned long buf[100]; };
 180#define __m(x) (*(struct __large_struct *)(x))
 181
 182#define __get_user_size(x,ptr,size,retval)                      \
 183do {                                                            \
 184        retval = 0;                                             \
 185        switch (size) {                                         \
 186        case 1:                                                 \
 187                __get_user_asm(x, ptr, retval, "b");            \
 188                break;                                          \
 189        case 2:                                                 \
 190                __get_user_asm(x, ptr, retval, "w");            \
 191                break;                                          \
 192        case 4:                                                 \
 193                __get_user_asm(x, ptr, retval, "l");            \
 194                break;                                          \
 195        default:                                                \
 196                __get_user_unknown();                           \
 197                break;                                          \
 198        }                                                       \
 199} while (0)
 200
 201#define __get_user_nocheck(x,ptr,size)                          \
 202({                                                              \
 203        long __gu_err, __gu_val;                                \
 204        __get_user_size(__gu_val, (ptr), (size), __gu_err);     \
 205        (x) = (__typeof__(*(ptr)))__gu_val;                     \
 206        __gu_err;                                               \
 207})
 208
 209#define __get_user_check(x,ptr,size)                            \
 210({                                                              \
 211        long __gu_err, __gu_val;                                \
 212        switch (size) {                                         \
 213        case 1:                                                 \
 214                __get_user_1(__gu_val, (ptr), __gu_err);        \
 215                break;                                          \
 216        case 2:                                                 \
 217                __get_user_2(__gu_val, (ptr), __gu_err);        \
 218                break;                                          \
 219        case 4:                                                 \
 220                __get_user_4(__gu_val, (ptr), __gu_err);        \
 221                break;                                          \
 222        default:                                                \
 223                __get_user_unknown();                           \
 224                break;                                          \
 225        }                                                       \
 226                                                                \
 227        (x) = (__typeof__(*(ptr)))__gu_val;                     \
 228        __gu_err;                                               \
 229})
 230
 231#define __get_user_1(x,addr,err) ({             \
 232__asm__("stc    r7_bank, %1\n\t"                \
 233        "mov.l  @(8,%1), %1\n\t"                \
 234        "and    %2, %1\n\t"                     \
 235        "cmp/pz %1\n\t"                         \
 236        "bt/s   1f\n\t"                         \
 237        " mov   #0, %0\n\t"                     \
 238        "0:\n"                                  \
 239        "mov    #-14, %0\n\t"                   \
 240        "bra    2f\n\t"                         \
 241        " mov   #0, %1\n"                       \
 242        "1:\n\t"                                \
 243        "mov.b  @%2, %1\n\t"                    \
 244        "extu.b %1, %1\n"                       \
 245        "2:\n"                                  \
 246        ".section       __ex_table,\"a\"\n\t"   \
 247        ".long  1b, 0b\n\t"                     \
 248        ".previous"                             \
 249        : "=&r" (err), "=&r" (x)                \
 250        : "r" (addr)                            \
 251        : "t");                                 \
 252})
 253
 254#define __get_user_2(x,addr,err) ({             \
 255__asm__("stc    r7_bank, %1\n\t"                \
 256        "mov.l  @(8,%1), %1\n\t"                \
 257        "and    %2, %1\n\t"                     \
 258        "cmp/pz %1\n\t"                         \
 259        "bt/s   1f\n\t"                         \
 260        " mov   #0, %0\n\t"                     \
 261        "0:\n"                                  \
 262        "mov    #-14, %0\n\t"                   \
 263        "bra    2f\n\t"                         \
 264        " mov   #0, %1\n"                       \
 265        "1:\n\t"                                \
 266        "mov.w  @%2, %1\n\t"                    \
 267        "extu.w %1, %1\n"                       \
 268        "2:\n"                                  \
 269        ".section       __ex_table,\"a\"\n\t"   \
 270        ".long  1b, 0b\n\t"                     \
 271        ".previous"                             \
 272        : "=&r" (err), "=&r" (x)                \
 273        : "r" (addr)                            \
 274        : "t");                                 \
 275})
 276
 277#define __get_user_4(x,addr,err) ({             \
 278__asm__("stc    r7_bank, %1\n\t"                \
 279        "mov.l  @(8,%1), %1\n\t"                \
 280        "and    %2, %1\n\t"                     \
 281        "cmp/pz %1\n\t"                         \
 282        "bt/s   1f\n\t"                         \
 283        " mov   #0, %0\n\t"                     \
 284        "0:\n"                                  \
 285        "mov    #-14, %0\n\t"                   \
 286        "bra    2f\n\t"                         \
 287        " mov   #0, %1\n"                       \
 288        "1:\n\t"                                \
 289        "mov.l  @%2, %1\n\t"                    \
 290        "2:\n"                                  \
 291        ".section       __ex_table,\"a\"\n\t"   \
 292        ".long  1b, 0b\n\t"                     \
 293        ".previous"                             \
 294        : "=&r" (err), "=&r" (x)                \
 295        : "r" (addr)                            \
 296        : "t");                                 \
 297})
 298
 299#define __get_user_asm(x, addr, err, insn) \
 300({ \
 301__asm__ __volatile__( \
 302        "1:\n\t" \
 303        "mov." insn "   %2, %1\n\t" \
 304        "mov    #0, %0\n" \
 305        "2:\n" \
 306        ".section       .fixup,\"ax\"\n" \
 307        "3:\n\t" \
 308        "mov    #0, %1\n\t" \
 309        "mov.l  4f, %0\n\t" \
 310        "jmp    @%0\n\t" \
 311        " mov   %3, %0\n" \
 312        "4:     .long   2b\n\t" \
 313        ".previous\n" \
 314        ".section       __ex_table,\"a\"\n\t" \
 315        ".long  1b, 3b\n\t" \
 316        ".previous" \
 317        :"=&r" (err), "=&r" (x) \
 318        :"m" (__m(addr)), "i" (-EFAULT)); })
 319
 320extern void __get_user_unknown(void);
 321
 322#define __put_user_size(x,ptr,size,retval)              \
 323do {                                                    \
 324        retval = 0;                                     \
 325        switch (size) {                                 \
 326        case 1:                                         \
 327                __put_user_asm(x, ptr, retval, "b");    \
 328                break;                                  \
 329        case 2:                                         \
 330                __put_user_asm(x, ptr, retval, "w");    \
 331                break;                                  \
 332        case 4:                                         \
 333                __put_user_asm(x, ptr, retval, "l");    \
 334                break;                                  \
 335        case 8:                                         \
 336                __put_user_u64(x, ptr, retval);         \
 337                break;                                  \
 338        default:                                        \
 339                __put_user_unknown();                   \
 340        }                                               \
 341} while (0)
 342
 343#define __put_user_nocheck(x,ptr,size)                  \
 344({                                                      \
 345        long __pu_err;                                  \
 346        __put_user_size((x),(ptr),(size),__pu_err);     \
 347        __pu_err;                                       \
 348})
 349
 350#define __put_user_check(x,ptr,size)                            \
 351({                                                              \
 352        long __pu_err = -EFAULT;                                \
 353        __typeof__(*(ptr)) *__pu_addr = (ptr);                  \
 354                                                                \
 355        if (__access_ok((unsigned long)__pu_addr,size))         \
 356                __put_user_size((x),__pu_addr,(size),__pu_err); \
 357        __pu_err;                                               \
 358})
 359
 360#define __put_user_asm(x, addr, err, insn) \
 361({ \
 362__asm__ __volatile__( \
 363        "1:\n\t" \
 364        "mov." insn "   %1, %2\n\t" \
 365        "mov    #0, %0\n" \
 366        "2:\n" \
 367        ".section       .fixup,\"ax\"\n" \
 368        "3:\n\t" \
 369        "nop\n\t" \
 370        "mov.l  4f, %0\n\t" \
 371        "jmp    @%0\n\t" \
 372        "mov    %3, %0\n" \
 373        "4:     .long   2b\n\t" \
 374        ".previous\n" \
 375        ".section       __ex_table,\"a\"\n\t" \
 376        ".long  1b, 3b\n\t" \
 377        ".previous" \
 378        :"=&r" (err) \
 379        :"r" (x), "m" (__m(addr)), "i" (-EFAULT) \
 380        :"memory"); })
 381
 382#if defined(__LITTLE_ENDIAN__)
 383#define __put_user_u64(val,addr,retval) \
 384({ \
 385__asm__ __volatile__( \
 386        "1:\n\t" \
 387        "mov.l  %R1,%2\n\t" \
 388        "mov.l  %S1,%T2\n\t" \
 389        "mov    #0,%0\n" \
 390        "2:\n" \
 391        ".section       .fixup,\"ax\"\n" \
 392        "3:\n\t" \
 393        "nop\n\t" \
 394        "mov.l  4f,%0\n\t" \
 395        "jmp    @%0\n\t" \
 396        " mov   %3,%0\n" \
 397        "4:     .long   2b\n\t" \
 398        ".previous\n" \
 399        ".section       __ex_table,\"a\"\n\t" \
 400        ".long  1b, 3b\n\t" \
 401        ".previous" \
 402        : "=r" (retval) \
 403        : "r" (val), "m" (__m(addr)), "i" (-EFAULT) \
 404        : "memory"); })
 405#else
 406#define __put_user_u64(val,addr,retval) \
 407({ \
 408__asm__ __volatile__( \
 409        "1:\n\t" \
 410        "mov.l  %S1,%2\n\t" \
 411        "mov.l  %R1,%T2\n\t" \
 412        "mov    #0,%0\n" \
 413        "2:\n" \
 414        ".section       .fixup,\"ax\"\n" \
 415        "3:\n\t" \
 416        "nop\n\t" \
 417        "mov.l  4f,%0\n\t" \
 418        "jmp    @%0\n\t" \
 419        " mov   %3,%0\n" \
 420        "4:     .long   2b\n\t" \
 421        ".previous\n" \
 422        ".section       __ex_table,\"a\"\n\t" \
 423        ".long  1b, 3b\n\t" \
 424        ".previous" \
 425        : "=r" (retval) \
 426        : "r" (val), "m" (__m(addr)), "i" (-EFAULT) \
 427        : "memory"); })
 428#endif
 429
 430extern void __put_user_unknown(void);
 431
 432/* Generic arbitrary sized copy.  */
 433/* Return the number of bytes NOT copied */
 434extern __kernel_size_t __copy_user(void *to, const void *from, __kernel_size_t n);
 435
 436#define copy_to_user(to,from,n) ({ \
 437void *__copy_to = (void *) (to); \
 438__kernel_size_t __copy_size = (__kernel_size_t) (n); \
 439__kernel_size_t __copy_res; \
 440if(__copy_size && __access_ok((unsigned long)__copy_to, __copy_size)) { \
 441__copy_res = __copy_user(__copy_to, (void *) (from), __copy_size); \
 442} else __copy_res = __copy_size; \
 443__copy_res; })
 444
 445#define __copy_to_user(to,from,n)               \
 446        __copy_user((void *)(to),               \
 447                    (void *)(from), n)
 448
 449#define __copy_to_user_inatomic __copy_to_user
 450#define __copy_from_user_inatomic __copy_from_user
 451
 452
 453#define copy_from_user(to,from,n) ({ \
 454void *__copy_to = (void *) (to); \
 455void *__copy_from = (void *) (from); \
 456__kernel_size_t __copy_size = (__kernel_size_t) (n); \
 457__kernel_size_t __copy_res; \
 458if(__copy_size && __access_ok((unsigned long)__copy_from, __copy_size)) { \
 459__copy_res = __copy_user(__copy_to, __copy_from, __copy_size); \
 460} else __copy_res = __copy_size; \
 461__copy_res; })
 462
 463#define __copy_from_user(to,from,n)             \
 464        __copy_user((void *)(to),               \
 465                    (void *)(from), n)
 466
 467/*
 468 * Clear the area and return remaining number of bytes
 469 * (on failure.  Usually it's 0.)
 470 */
 471extern __kernel_size_t __clear_user(void *addr, __kernel_size_t size);
 472
 473#define clear_user(addr,n) ({ \
 474void * __cl_addr = (addr); \
 475unsigned long __cl_size = (n); \
 476if (__cl_size && __access_ok(((unsigned long)(__cl_addr)), __cl_size)) \
 477__cl_size = __clear_user(__cl_addr, __cl_size); \
 478__cl_size; })
 479
 480static __inline__ int
 481__strncpy_from_user(unsigned long __dest, unsigned long __user __src, int __count)
 482{
 483        __kernel_size_t res;
 484        unsigned long __dummy, _d, _s;
 485
 486        __asm__ __volatile__(
 487                "9:\n"
 488                "mov.b  @%2+, %1\n\t"
 489                "cmp/eq #0, %1\n\t"
 490                "bt/s   2f\n"
 491                "1:\n"
 492                "mov.b  %1, @%3\n\t"
 493                "dt     %7\n\t"
 494                "bf/s   9b\n\t"
 495                " add   #1, %3\n\t"
 496                "2:\n\t"
 497                "sub    %7, %0\n"
 498                "3:\n"
 499                ".section .fixup,\"ax\"\n"
 500                "4:\n\t"
 501                "mov.l  5f, %1\n\t"
 502                "jmp    @%1\n\t"
 503                " mov   %8, %0\n\t"
 504                ".balign 4\n"
 505                "5:     .long 3b\n"
 506                ".previous\n"
 507                ".section __ex_table,\"a\"\n"
 508                "       .balign 4\n"
 509                "       .long 9b,4b\n"
 510                ".previous"
 511                : "=r" (res), "=&z" (__dummy), "=r" (_s), "=r" (_d)
 512                : "0" (__count), "2" (__src), "3" (__dest), "r" (__count),
 513                  "i" (-EFAULT)
 514                : "memory", "t");
 515
 516        return res;
 517}
 518
 519#define strncpy_from_user(dest,src,count) ({ \
 520unsigned long __sfu_src = (unsigned long) (src); \
 521int __sfu_count = (int) (count); \
 522long __sfu_res = -EFAULT; \
 523if(__access_ok(__sfu_src, __sfu_count)) { \
 524__sfu_res = __strncpy_from_user((unsigned long) (dest), __sfu_src, __sfu_count); \
 525} __sfu_res; })
 526
 527/*
 528 * Return the size of a string (including the ending 0!)
 529 */
 530static __inline__ long __strnlen_user(const char __user *__s, long __n)
 531{
 532        unsigned long res;
 533        unsigned long __dummy;
 534
 535        __asm__ __volatile__(
 536                "9:\n"
 537                "cmp/eq %4, %0\n\t"
 538                "bt     2f\n"
 539                "1:\t"
 540                "mov.b  @(%0,%3), %1\n\t"
 541                "tst    %1, %1\n\t"
 542                "bf/s   9b\n\t"
 543                " add   #1, %0\n"
 544                "2:\n"
 545                ".section .fixup,\"ax\"\n"
 546                "3:\n\t"
 547                "mov.l  4f, %1\n\t"
 548                "jmp    @%1\n\t"
 549                " mov   %5, %0\n"
 550                ".balign 4\n"
 551                "4:     .long 2b\n"
 552                ".previous\n"
 553                ".section __ex_table,\"a\"\n"
 554                "       .balign 4\n"
 555                "       .long 1b,3b\n"
 556                ".previous"
 557                : "=z" (res), "=&r" (__dummy)
 558                : "0" (0), "r" (__s), "r" (__n), "i" (-EFAULT)
 559                : "t");
 560        return res;
 561}
 562
 563static __inline__ long strnlen_user(const char __user *s, long n)
 564{
 565        if (!access_ok(VERIFY_READ, s, n))
 566                return 0;
 567        else
 568                return __strnlen_user(s, n);
 569}
 570
 571static __inline__ long strlen_user(const char __user *s)
 572{
 573        if (!access_ok(VERIFY_READ, s, 0))
 574                return 0;
 575        else
 576                return __strnlen_user(s, ~0UL >> 1);
 577}
 578
 579/*
 580 * The exception table consists of pairs of addresses: the first is the
 581 * address of an instruction that is allowed to fault, and the second is
 582 * the address at which the program should continue.  No registers are
 583 * modified, so it is entirely up to the continuation code to figure out
 584 * what to do.
 585 *
 586 * All the routines below use bits of fixup code that are out of line
 587 * with the main instruction path.  This means when everything is well,
 588 * we don't even have to jump over them.  Further, they do not intrude
 589 * on our cache or tlb entries.
 590 */
 591
 592struct exception_table_entry
 593{
 594        unsigned long insn, fixup;
 595};
 596
 597extern int fixup_exception(struct pt_regs *regs);
 598
 599#endif /* __ASM_SH_UACCESS_H */
 600
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.