linux/arch/csky/lib/usercopy.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2// Copyright (C) 2018 Hangzhou C-SKY Microsystems co.,ltd.
   3
   4#include <linux/uaccess.h>
   5#include <linux/types.h>
   6
   7unsigned long raw_copy_from_user(void *to, const void *from,
   8                        unsigned long n)
   9{
  10        if (access_ok(from, n))
  11                __copy_user_zeroing(to, from, n);
  12        else
  13                memset(to, 0, n);
  14        return n;
  15}
  16EXPORT_SYMBOL(raw_copy_from_user);
  17
  18unsigned long raw_copy_to_user(void *to, const void *from,
  19                        unsigned long n)
  20{
  21        if (access_ok(to, n))
  22                __copy_user(to, from, n);
  23        return n;
  24}
  25EXPORT_SYMBOL(raw_copy_to_user);
  26
  27
  28/*
  29 * copy a null terminated string from userspace.
  30 */
  31#define __do_strncpy_from_user(dst, src, count, res)    \
  32do {                                                    \
  33        int tmp;                                        \
  34        long faultres;                                  \
  35        asm volatile(                                   \
  36        "       cmpnei  %3, 0           \n"             \
  37        "       bf      4f              \n"             \
  38        "1:     cmpnei  %1, 0           \n"             \
  39        "       bf      5f              \n"             \
  40        "2:     ldb     %4, (%3, 0)     \n"             \
  41        "       stb     %4, (%2, 0)     \n"             \
  42        "       cmpnei  %4, 0           \n"             \
  43        "       bf      3f              \n"             \
  44        "       addi    %3,  1          \n"             \
  45        "       addi    %2,  1          \n"             \
  46        "       subi    %1,  1          \n"             \
  47        "       br      1b              \n"             \
  48        "3:     subu    %0, %1          \n"             \
  49        "       br      5f              \n"             \
  50        "4:     mov     %0, %5          \n"             \
  51        "       br      5f              \n"             \
  52        ".section __ex_table, \"a\"     \n"             \
  53        ".align   2                     \n"             \
  54        ".long    2b, 4b                \n"             \
  55        ".previous                      \n"             \
  56        "5:                             \n"             \
  57        : "=r"(res), "=r"(count), "=r"(dst),            \
  58          "=r"(src), "=r"(tmp),   "=r"(faultres)        \
  59        : "5"(-EFAULT), "0"(count), "1"(count),         \
  60          "2"(dst), "3"(src)                            \
  61        : "memory", "cc");                              \
  62} while (0)
  63
  64/*
  65 * __strncpy_from_user: - Copy a NUL terminated string from userspace,
  66 * with less checking.
  67 * @dst:   Destination address, in kernel space.  This buffer must be at
  68 *         least @count bytes long.
  69 * @src:   Source address, in user space.
  70 * @count: Maximum number of bytes to copy, including the trailing NUL.
  71 *
  72 * Copies a NUL-terminated string from userspace to kernel space.
  73 * Caller must check the specified block with access_ok() before calling
  74 * this function.
  75 *
  76 * On success, returns the length of the string (not including the trailing
  77 * NUL).
  78 *
  79 * If access to userspace fails, returns -EFAULT (some data may have been
  80 * copied).
  81 *
  82 * If @count is smaller than the length of the string, copies @count bytes
  83 * and returns @count.
  84 */
  85long __strncpy_from_user(char *dst, const char *src, long count)
  86{
  87        long res;
  88
  89        __do_strncpy_from_user(dst, src, count, res);
  90        return res;
  91}
  92EXPORT_SYMBOL(__strncpy_from_user);
  93
  94/*
  95 * strncpy_from_user: - Copy a NUL terminated string from userspace.
  96 * @dst:   Destination address, in kernel space.  This buffer must be at
  97 *         least @count bytes long.
  98 * @src:   Source address, in user space.
  99 * @count: Maximum number of bytes to copy, including the trailing NUL.
 100 *
 101 * Copies a NUL-terminated string from userspace to kernel space.
 102 *
 103 * On success, returns the length of the string (not including the trailing
 104 * NUL).
 105 *
 106 * If access to userspace fails, returns -EFAULT (some data may have been
 107 * copied).
 108 *
 109 * If @count is smaller than the length of the string, copies @count bytes
 110 * and returns @count.
 111 */
 112long strncpy_from_user(char *dst, const char *src, long count)
 113{
 114        long res = -EFAULT;
 115
 116        if (access_ok(src, 1))
 117                __do_strncpy_from_user(dst, src, count, res);
 118        return res;
 119}
 120EXPORT_SYMBOL(strncpy_from_user);
 121
 122/*
 123 * strlen_user: - Get the size of a string in user space.
 124 * @str: The string to measure.
 125 * @n:   The maximum valid length
 126 *
 127 * Get the size of a NUL-terminated string in user space.
 128 *
 129 * Returns the size of the string INCLUDING the terminating NUL.
 130 * On exception, returns 0.
 131 * If the string is too long, returns a value greater than @n.
 132 */
 133long strnlen_user(const char *s, long n)
 134{
 135        unsigned long res, tmp;
 136
 137        if (s == NULL)
 138                return 0;
 139
 140        asm volatile(
 141        "       cmpnei  %1, 0           \n"
 142        "       bf      3f              \n"
 143        "1:     cmpnei  %0, 0           \n"
 144        "       bf      3f              \n"
 145        "2:     ldb     %3, (%1, 0)     \n"
 146        "       cmpnei  %3, 0           \n"
 147        "       bf      3f              \n"
 148        "       subi    %0,  1          \n"
 149        "       addi    %1,  1          \n"
 150        "       br      1b              \n"
 151        "3:     subu    %2, %0          \n"
 152        "       addi    %2,  1          \n"
 153        "       br      5f              \n"
 154        "4:     movi    %0, 0           \n"
 155        "       br      5f              \n"
 156        ".section __ex_table, \"a\"     \n"
 157        ".align   2                     \n"
 158        ".long    2b, 4b                \n"
 159        ".previous                      \n"
 160        "5:                             \n"
 161        : "=r"(n), "=r"(s), "=r"(res), "=r"(tmp)
 162        : "0"(n), "1"(s), "2"(n)
 163        : "memory", "cc");
 164
 165        return res;
 166}
 167EXPORT_SYMBOL(strnlen_user);
 168
 169#define __do_clear_user(addr, size)                     \
 170do {                                                    \
 171        int __d0, zvalue, tmp;                          \
 172                                                        \
 173        asm volatile(                                   \
 174        "0:     cmpnei  %1, 0           \n"             \
 175        "       bf      7f              \n"             \
 176        "       mov     %3, %1          \n"             \
 177        "       andi    %3, 3           \n"             \
 178        "       cmpnei  %3, 0           \n"             \
 179        "       bf      1f              \n"             \
 180        "       br      5f              \n"             \
 181        "1:     cmplti  %0, 32          \n" /* 4W */    \
 182        "       bt      3f              \n"             \
 183        "8:     stw     %2, (%1, 0)     \n"             \
 184        "10:    stw     %2, (%1, 4)     \n"             \
 185        "11:    stw     %2, (%1, 8)     \n"             \
 186        "12:    stw     %2, (%1, 12)    \n"             \
 187        "13:    stw     %2, (%1, 16)    \n"             \
 188        "14:    stw     %2, (%1, 20)    \n"             \
 189        "15:    stw     %2, (%1, 24)    \n"             \
 190        "16:    stw     %2, (%1, 28)    \n"             \
 191        "       addi    %1, 32          \n"             \
 192        "       subi    %0, 32          \n"             \
 193        "       br      1b              \n"             \
 194        "3:     cmplti  %0, 4           \n" /* 1W */    \
 195        "       bt      5f              \n"             \
 196        "4:     stw     %2, (%1, 0)     \n"             \
 197        "       addi    %1, 4           \n"             \
 198        "       subi    %0, 4           \n"             \
 199        "       br      3b              \n"             \
 200        "5:     cmpnei  %0, 0           \n" /* 1B */    \
 201        "9:     bf      7f              \n"             \
 202        "6:     stb     %2, (%1, 0)     \n"             \
 203        "       addi    %1,  1          \n"             \
 204        "       subi    %0,  1          \n"             \
 205        "       br      5b              \n"             \
 206        ".section __ex_table,\"a\"      \n"             \
 207        ".align   2                     \n"             \
 208        ".long    8b, 9b                \n"             \
 209        ".long    10b, 9b               \n"             \
 210        ".long    11b, 9b               \n"             \
 211        ".long    12b, 9b               \n"             \
 212        ".long    13b, 9b               \n"             \
 213        ".long    14b, 9b               \n"             \
 214        ".long    15b, 9b               \n"             \
 215        ".long    16b, 9b               \n"             \
 216        ".long    4b, 9b                \n"             \
 217        ".long    6b, 9b                \n"             \
 218        ".previous                      \n"             \
 219        "7:                             \n"             \
 220        : "=r"(size), "=r" (__d0),                      \
 221          "=r"(zvalue), "=r"(tmp)                       \
 222        : "0"(size), "1"(addr), "2"(0)                  \
 223        : "memory", "cc");                              \
 224} while (0)
 225
 226/*
 227 * clear_user: - Zero a block of memory in user space.
 228 * @to:   Destination address, in user space.
 229 * @n:    Number of bytes to zero.
 230 *
 231 * Zero a block of memory in user space.
 232 *
 233 * Returns number of bytes that could not be cleared.
 234 * On success, this will be zero.
 235 */
 236unsigned long
 237clear_user(void __user *to, unsigned long n)
 238{
 239        if (access_ok(to, n))
 240                __do_clear_user(to, n);
 241        return n;
 242}
 243EXPORT_SYMBOL(clear_user);
 244
 245/*
 246 * __clear_user: - Zero a block of memory in user space, with less checking.
 247 * @to:   Destination address, in user space.
 248 * @n:    Number of bytes to zero.
 249 *
 250 * Zero a block of memory in user space.  Caller must check
 251 * the specified block with access_ok() before calling this function.
 252 *
 253 * Returns number of bytes that could not be cleared.
 254 * On success, this will be zero.
 255 */
 256unsigned long
 257__clear_user(void __user *to, unsigned long n)
 258{
 259        __do_clear_user(to, n);
 260        return n;
 261}
 262EXPORT_SYMBOL(__clear_user);
 263