linux/arch/frv/include/asm/uaccess.h
<<
>>
Prefs
   1/* uaccess.h: userspace accessor functions
   2 *
   3 * Copyright (C) 2004 Red Hat, Inc. All Rights Reserved.
   4 * Written by David Howells (dhowells@redhat.com)
   5 *
   6 * This program is free software; you can redistribute it and/or
   7 * modify it under the terms of the GNU General Public License
   8 * as published by the Free Software Foundation; either version
   9 * 2 of the License, or (at your option) any later version.
  10 */
  11
  12#ifndef _ASM_UACCESS_H
  13#define _ASM_UACCESS_H
  14
  15/*
  16 * User space memory access functions
  17 */
  18#include <linux/mm.h>
  19#include <asm/segment.h>
  20#include <asm/sections.h>
  21#include <asm/extable.h>
  22
  23#define __ptr(x) ((unsigned long __force *)(x))
  24
  25/*
  26 * check that a range of addresses falls within the current address limit
  27 */
  28static inline int ___range_ok(unsigned long addr, unsigned long size)
  29{
  30#ifdef CONFIG_MMU
  31        int flag = -EFAULT, tmp;
  32
  33        asm volatile (
  34                "       addcc   %3,%2,%1,icc0   \n"     /* set C-flag if addr+size>4GB */
  35                "       subcc.p %1,%4,gr0,icc1  \n"     /* jump if addr+size>limit */
  36                "       bc      icc0,#0,0f      \n"
  37                "       bhi     icc1,#0,0f      \n"
  38                "       setlos  #0,%0           \n"     /* mark okay */
  39                "0:                             \n"
  40                : "=r"(flag), "=&r"(tmp)
  41                : "r"(addr), "r"(size), "r"(get_addr_limit()), "0"(flag)
  42                );
  43
  44        return flag;
  45
  46#else
  47
  48        if (addr < memory_start ||
  49            addr > memory_end ||
  50            size > memory_end - memory_start ||
  51            addr + size > memory_end)
  52                return -EFAULT;
  53
  54        return 0;
  55#endif
  56}
  57
  58#define __range_ok(addr,size) ___range_ok((unsigned long) (addr), (unsigned long) (size))
  59
  60#define access_ok(type,addr,size) (__range_ok((void __user *)(addr), (size)) == 0)
  61#define __access_ok(addr,size) (__range_ok((addr), (size)) == 0)
  62
  63
  64/*
  65 * These are the main single-value transfer routines.  They automatically
  66 * use the right size if we just have the right pointer type.
  67 */
  68#define __put_user(x, ptr)                                              \
  69({                                                                      \
  70        int __pu_err = 0;                                               \
  71                                                                        \
  72        typeof(*(ptr)) __pu_val = (x);                                  \
  73        __chk_user_ptr(ptr);                                            \
  74                                                                        \
  75        switch (sizeof (*(ptr))) {                                      \
  76        case 1:                                                         \
  77                __put_user_asm(__pu_err, __pu_val, ptr, "b", "r");      \
  78                break;                                                  \
  79        case 2:                                                         \
  80                __put_user_asm(__pu_err, __pu_val, ptr, "h", "r");      \
  81                break;                                                  \
  82        case 4:                                                         \
  83                __put_user_asm(__pu_err, __pu_val, ptr, "",  "r");      \
  84                break;                                                  \
  85        case 8:                                                         \
  86                __put_user_asm(__pu_err, __pu_val, ptr, "d", "e");      \
  87                break;                                                  \
  88        default:                                                        \
  89                __pu_err = __put_user_bad();                            \
  90                break;                                                  \
  91        }                                                               \
  92        __pu_err;                                                       \
  93})
  94
  95#define put_user(x, ptr)                        \
  96({                                              \
  97        typeof(*(ptr)) __user *_p = (ptr);      \
  98        int _e;                                 \
  99                                                \
 100        _e = __range_ok(_p, sizeof(*_p));       \
 101        if (_e == 0)                            \
 102                _e = __put_user((x), _p);       \
 103        _e;                                     \
 104})
 105
 106extern int __put_user_bad(void);
 107
 108/*
 109 * Tell gcc we read from memory instead of writing: this is because
 110 * we do not write to any memory gcc knows about, so there are no
 111 * aliasing issues.
 112 */
 113
 114#ifdef CONFIG_MMU
 115
 116#define __put_user_asm(err,x,ptr,dsize,constraint)                                      \
 117do {                                                                                    \
 118        asm volatile("1:        st"dsize"%I1    %2,%M1  \n"                             \
 119                     "2:                                \n"                             \
 120                     ".subsection 2                     \n"                             \
 121                     "3:        setlos          %3,%0   \n"                             \
 122                     "          bra             2b      \n"                             \
 123                     ".previous                         \n"                             \
 124                     ".section __ex_table,\"a\"         \n"                             \
 125                     "          .balign         8       \n"                             \
 126                     "          .long           1b,3b   \n"                             \
 127                     ".previous"                                                        \
 128                     : "=r" (err)                                                       \
 129                     : "m" (*__ptr(ptr)), constraint (x), "i"(-EFAULT), "0"(err)        \
 130                     : "memory");                                                       \
 131} while (0)
 132
 133#else
 134
 135#define __put_user_asm(err,x,ptr,bwl,con)       \
 136do {                                            \
 137        asm("   st"bwl"%I0      %1,%M0  \n"     \
 138            "   membar                  \n"     \
 139            :                                   \
 140            : "m" (*__ptr(ptr)), con (x)        \
 141            : "memory");                        \
 142} while (0)
 143
 144#endif
 145
 146/*****************************************************************************/
 147/*
 148 *
 149 */
 150#define __get_user(x, ptr)                                              \
 151({                                                                      \
 152        int __gu_err = 0;                                               \
 153        __chk_user_ptr(ptr);                                            \
 154                                                                        \
 155        switch (sizeof(*(ptr))) {                                       \
 156        case 1: {                                                       \
 157                unsigned char __gu_val;                                 \
 158                __get_user_asm(__gu_err, __gu_val, ptr, "ub", "=r");    \
 159                (x) = *(__force __typeof__(*(ptr)) *) &__gu_val;        \
 160                break;                                                  \
 161        }                                                               \
 162        case 2: {                                                       \
 163                unsigned short __gu_val;                                \
 164                __get_user_asm(__gu_err, __gu_val, ptr, "uh", "=r");    \
 165                (x) = *(__force __typeof__(*(ptr)) *) &__gu_val;        \
 166                break;                                                  \
 167        }                                                               \
 168        case 4: {                                                       \
 169                unsigned int __gu_val;                                  \
 170                __get_user_asm(__gu_err, __gu_val, ptr, "", "=r");      \
 171                (x) = *(__force __typeof__(*(ptr)) *) &__gu_val;        \
 172                break;                                                  \
 173        }                                                               \
 174        case 8: {                                                       \
 175                unsigned long long __gu_val;                            \
 176                __get_user_asm(__gu_err, __gu_val, ptr, "d", "=e");     \
 177                (x) = *(__force __typeof__(*(ptr)) *) &__gu_val;        \
 178                break;                                                  \
 179        }                                                               \
 180        default:                                                        \
 181                __gu_err = __get_user_bad();                            \
 182                break;                                                  \
 183        }                                                               \
 184        __gu_err;                                                       \
 185})
 186
 187#define get_user(x, ptr)                        \
 188({                                              \
 189        const typeof(*(ptr)) __user *_p = (ptr);\
 190        int _e;                                 \
 191                                                \
 192        _e = __range_ok(_p, sizeof(*_p));       \
 193        if (likely(_e == 0))                    \
 194                _e = __get_user((x), _p);       \
 195        else                                    \
 196                (x) = (typeof(x)) 0;            \
 197        _e;                                     \
 198})
 199
 200extern int __get_user_bad(void);
 201
 202#ifdef CONFIG_MMU
 203
 204#define __get_user_asm(err,x,ptr,dtype,constraint)      \
 205do {                                                    \
 206        asm("1:         ld"dtype"%I2    %M2,%1  \n"     \
 207            "2:                                 \n"     \
 208            ".subsection 2                      \n"     \
 209            "3:         setlos          %3,%0   \n"     \
 210            "           setlos          #0,%1   \n"     \
 211            "           bra             2b      \n"     \
 212            ".previous                          \n"     \
 213            ".section __ex_table,\"a\"          \n"     \
 214            "           .balign         8       \n"     \
 215            "           .long           1b,3b   \n"     \
 216            ".previous"                                 \
 217            : "=r" (err), constraint (x)                \
 218            : "m" (*__ptr(ptr)), "i"(-EFAULT), "0"(err) \
 219            );                                          \
 220} while(0)
 221
 222#else
 223
 224#define __get_user_asm(err,x,ptr,bwl,con)       \
 225        asm("   ld"bwl"%I1      %M1,%0  \n"     \
 226            "   membar                  \n"     \
 227            : con(x)                            \
 228            : "m" (*__ptr(ptr)))
 229
 230#endif
 231
 232/*****************************************************************************/
 233/*
 234 *
 235 */
 236
 237#define ____force(x) (__force void *)(void __user *)(x)
 238#ifdef CONFIG_MMU
 239extern long __memset_user(void *dst, unsigned long count);
 240extern long __memcpy_user(void *dst, const void *src, unsigned long count);
 241
 242#define __clear_user(dst,count)                 __memset_user(____force(dst), (count))
 243
 244#else
 245
 246#define __clear_user(dst,count)                 (memset(____force(dst), 0, (count)), 0)
 247
 248#endif
 249
 250static inline unsigned long
 251raw_copy_from_user(void *to, const void __user *from, unsigned long n)
 252{
 253#ifdef CONFIG_MMU
 254        return __memcpy_user(to, (__force const void *)from, n);
 255#else
 256        memcpy(to, (__force const void *)from, n);
 257        return 0;
 258#endif
 259}
 260
 261static inline unsigned long
 262raw_copy_to_user(void __user *to, const void *from, unsigned long n)
 263{
 264#ifdef CONFIG_MMU
 265        return __memcpy_user((__force void *)to, from, n);
 266#else
 267        memcpy((__force void *)to, from, n);
 268        return 0;
 269#endif
 270}
 271#define INLINE_COPY_TO_USER
 272#define INLINE_COPY_FROM_USER
 273
 274static inline unsigned long __must_check
 275clear_user(void __user *to, unsigned long n)
 276{
 277        if (likely(__access_ok(to, n)))
 278                n = __clear_user(to, n);
 279        return n;
 280}
 281
 282extern long strncpy_from_user(char *dst, const char __user *src, long count);
 283extern long strnlen_user(const char __user *src, long count);
 284
 285#endif /* _ASM_UACCESS_H */
 286