linux/arch/m32r/lib/usercopy.c
<<
>>
Prefs
   1/*
   2 * User address space access functions.
   3 * The non inlined parts of asm-m32r/uaccess.h are here.
   4 *
   5 * Copyright 1997 Andi Kleen <ak@muc.de>
   6 * Copyright 1997 Linus Torvalds
   7 * Copyright 2001, 2002, 2004 Hirokazu Takata
   8 */
   9#include <linux/prefetch.h>
  10#include <linux/string.h>
  11#include <linux/thread_info.h>
  12#include <asm/uaccess.h>
  13
  14unsigned long
  15__generic_copy_to_user(void __user *to, const void *from, unsigned long n)
  16{
  17        prefetch(from);
  18        if (access_ok(VERIFY_WRITE, to, n))
  19                __copy_user(to,from,n);
  20        return n;
  21}
  22
  23unsigned long
  24__generic_copy_from_user(void *to, const void __user *from, unsigned long n)
  25{
  26        prefetchw(to);
  27        if (access_ok(VERIFY_READ, from, n))
  28                __copy_user_zeroing(to,from,n);
  29        else
  30                memset(to, 0, n);
  31        return n;
  32}
  33
  34
  35/*
  36 * Copy a null terminated string from userspace.
  37 */
  38
  39#ifdef CONFIG_ISA_DUAL_ISSUE
  40
  41#define __do_strncpy_from_user(dst,src,count,res)                       \
  42do {                                                                    \
  43        int __d0, __d1, __d2;                                           \
  44        __asm__ __volatile__(                                           \
  45                "       beqz    %1, 2f\n"                               \
  46                "       .fillinsn\n"                                    \
  47                "0:     ldb     r14, @%3    ||  addi    %3, #1\n"       \
  48                "       stb     r14, @%4    ||  addi    %4, #1\n"       \
  49                "       beqz    r14, 1f\n"                              \
  50                "       addi    %1, #-1\n"                              \
  51                "       bnez    %1, 0b\n"                               \
  52                "       .fillinsn\n"                                    \
  53                "1:     sub     %0, %1\n"                               \
  54                "       .fillinsn\n"                                    \
  55                "2:\n"                                                  \
  56                ".section .fixup,\"ax\"\n"                              \
  57                "       .balign 4\n"                                    \
  58                "3:     seth    r14, #high(2b)\n"                       \
  59                "       or3     r14, r14, #low(2b)\n"                   \
  60                "       jmp     r14         ||  ldi     %0, #%5\n"      \
  61                ".previous\n"                                           \
  62                ".section __ex_table,\"a\"\n"                           \
  63                "       .balign 4\n"                                    \
  64                "       .long 0b,3b\n"                                  \
  65                ".previous"                                             \
  66                : "=&r"(res), "=&r"(count), "=&r" (__d0), "=&r" (__d1), \
  67                  "=&r" (__d2)                                          \
  68                : "i"(-EFAULT), "0"(count), "1"(count), "3"(src),       \
  69                  "4"(dst)                                              \
  70                : "r14", "cbit", "memory");                             \
  71} while (0)
  72
  73#else /* not CONFIG_ISA_DUAL_ISSUE */
  74
  75#define __do_strncpy_from_user(dst,src,count,res)                       \
  76do {                                                                    \
  77        int __d0, __d1, __d2;                                           \
  78        __asm__ __volatile__(                                           \
  79                "       beqz    %1, 2f\n"                               \
  80                "       .fillinsn\n"                                    \
  81                "0:     ldb     r14, @%3\n"                             \
  82                "       stb     r14, @%4\n"                             \
  83                "       addi    %3, #1\n"                               \
  84                "       addi    %4, #1\n"                               \
  85                "       beqz    r14, 1f\n"                              \
  86                "       addi    %1, #-1\n"                              \
  87                "       bnez    %1, 0b\n"                               \
  88                "       .fillinsn\n"                                    \
  89                "1:     sub     %0, %1\n"                               \
  90                "       .fillinsn\n"                                    \
  91                "2:\n"                                                  \
  92                ".section .fixup,\"ax\"\n"                              \
  93                "       .balign 4\n"                                    \
  94                "3:     ldi     %0, #%5\n"                              \
  95                "       seth    r14, #high(2b)\n"                       \
  96                "       or3     r14, r14, #low(2b)\n"                   \
  97                "       jmp     r14\n"                                  \
  98                ".previous\n"                                           \
  99                ".section __ex_table,\"a\"\n"                           \
 100                "       .balign 4\n"                                    \
 101                "       .long 0b,3b\n"                                  \
 102                ".previous"                                             \
 103                : "=&r"(res), "=&r"(count), "=&r" (__d0), "=&r" (__d1), \
 104                  "=&r" (__d2)                                          \
 105                : "i"(-EFAULT), "0"(count), "1"(count), "3"(src),       \
 106                  "4"(dst)                                              \
 107                : "r14", "cbit", "memory");                             \
 108} while (0)
 109
 110#endif /* CONFIG_ISA_DUAL_ISSUE */
 111
 112long
 113__strncpy_from_user(char *dst, const char __user *src, long count)
 114{
 115        long res;
 116        __do_strncpy_from_user(dst, src, count, res);
 117        return res;
 118}
 119
 120long
 121strncpy_from_user(char *dst, const char __user *src, long count)
 122{
 123        long res = -EFAULT;
 124        if (access_ok(VERIFY_READ, src, 1))
 125                __do_strncpy_from_user(dst, src, count, res);
 126        return res;
 127}
 128
 129
 130/*
 131 * Zero Userspace
 132 */
 133
 134#ifdef CONFIG_ISA_DUAL_ISSUE
 135
 136#define __do_clear_user(addr,size)                                      \
 137do {                                                                    \
 138        int __dst, __c;                                                 \
 139        __asm__ __volatile__(                                           \
 140                "       beqz    %1, 9f\n"                               \
 141                "       and3    r14, %0, #3\n"                          \
 142                "       bnez    r14, 2f\n"                              \
 143                "       and3    r14, %1, #3\n"                          \
 144                "       bnez    r14, 2f\n"                              \
 145                "       and3    %1, %1, #3\n"                           \
 146                "       beqz    %2, 2f\n"                               \
 147                "       addi    %0, #-4\n"                              \
 148                "       .fillinsn\n"                                    \
 149                "0:     ; word clear \n"                                \
 150                "       st      %6, @+%0    ||  addi    %2, #-1\n"      \
 151                "       bnez    %2, 0b\n"                               \
 152                "       beqz    %1, 9f\n"                               \
 153                "       .fillinsn\n"                                    \
 154                "2:     ; byte clear \n"                                \
 155                "       stb     %6, @%0     ||  addi    %1, #-1\n"      \
 156                "       addi    %0, #1\n"                               \
 157                "       bnez    %1, 2b\n"                               \
 158                "       .fillinsn\n"                                    \
 159                "9:\n"                                                  \
 160                ".section .fixup,\"ax\"\n"                              \
 161                "       .balign 4\n"                                    \
 162                "4:     slli    %2, #2\n"                               \
 163                "       seth    r14, #high(9b)\n"                       \
 164                "       or3     r14, r14, #low(9b)\n"                   \
 165                "       jmp     r14         ||  add     %1, %2\n"       \
 166                ".previous\n"                                           \
 167                ".section __ex_table,\"a\"\n"                           \
 168                "       .balign 4\n"                                    \
 169                "       .long 0b,4b\n"                                  \
 170                "       .long 2b,9b\n"                                  \
 171                ".previous\n"                                           \
 172                : "=&r"(__dst), "=&r"(size), "=&r"(__c)                 \
 173                : "0"(addr), "1"(size), "2"(size / 4), "r"(0)           \
 174                : "r14", "cbit", "memory");                             \
 175} while (0)
 176
 177#else /* not CONFIG_ISA_DUAL_ISSUE */
 178
 179#define __do_clear_user(addr,size)                                      \
 180do {                                                                    \
 181        int __dst, __c;                                                 \
 182        __asm__ __volatile__(                                           \
 183                "       beqz    %1, 9f\n"                               \
 184                "       and3    r14, %0, #3\n"                          \
 185                "       bnez    r14, 2f\n"                              \
 186                "       and3    r14, %1, #3\n"                          \
 187                "       bnez    r14, 2f\n"                              \
 188                "       and3    %1, %1, #3\n"                           \
 189                "       beqz    %2, 2f\n"                               \
 190                "       addi    %0, #-4\n"                              \
 191                "       .fillinsn\n"                                    \
 192                "0:     st      %6, @+%0        ; word clear \n"        \
 193                "       addi    %2, #-1\n"                              \
 194                "       bnez    %2, 0b\n"                               \
 195                "       beqz    %1, 9f\n"                               \
 196                "       .fillinsn\n"                                    \
 197                "2:     stb     %6, @%0         ; byte clear \n"        \
 198                "       addi    %1, #-1\n"                              \
 199                "       addi    %0, #1\n"                               \
 200                "       bnez    %1, 2b\n"                               \
 201                "       .fillinsn\n"                                    \
 202                "9:\n"                                                  \
 203                ".section .fixup,\"ax\"\n"                              \
 204                "       .balign 4\n"                                    \
 205                "4:     slli    %2, #2\n"                               \
 206                "       add     %1, %2\n"                               \
 207                "       seth    r14, #high(9b)\n"                       \
 208                "       or3     r14, r14, #low(9b)\n"                   \
 209                "       jmp     r14\n"                                  \
 210                ".previous\n"                                           \
 211                ".section __ex_table,\"a\"\n"                           \
 212                "       .balign 4\n"                                    \
 213                "       .long 0b,4b\n"                                  \
 214                "       .long 2b,9b\n"                                  \
 215                ".previous\n"                                           \
 216                : "=&r"(__dst), "=&r"(size), "=&r"(__c)                 \
 217                : "0"(addr), "1"(size), "2"(size / 4), "r"(0)           \
 218                : "r14", "cbit", "memory");                             \
 219} while (0)
 220
 221#endif /* not CONFIG_ISA_DUAL_ISSUE */
 222
 223unsigned long
 224clear_user(void __user *to, unsigned long n)
 225{
 226        if (access_ok(VERIFY_WRITE, to, n))
 227                __do_clear_user(to, n);
 228        return n;
 229}
 230
 231unsigned long
 232__clear_user(void __user *to, unsigned long n)
 233{
 234        __do_clear_user(to, n);
 235        return n;
 236}
 237
 238/*
 239 * Return the size of a string (including the ending 0)
 240 *
 241 * Return 0 on exception, a value greater than N if too long
 242 */
 243
 244#ifdef CONFIG_ISA_DUAL_ISSUE
 245
 246long strnlen_user(const char __user *s, long n)
 247{
 248        unsigned long mask = -__addr_ok(s);
 249        unsigned long res;
 250
 251        __asm__ __volatile__(
 252                "       and     %0, %5      ||  mv      r1, %1\n"
 253                "       beqz    %0, strnlen_exit\n"
 254                "       and3    r0, %1, #3\n"
 255                "       bnez    r0, strnlen_byte_loop\n"
 256                "       cmpui   %0, #4\n"
 257                "       bc      strnlen_byte_loop\n"
 258                "strnlen_word_loop:\n"
 259                "0:     ld      r0, @%1+\n"
 260                "       pcmpbz  r0\n"
 261                "       bc      strnlen_last_bytes_fixup\n"
 262                "       addi    %0, #-4\n"
 263                "       beqz    %0, strnlen_exit\n"
 264                "       bgtz    %0, strnlen_word_loop\n"
 265                "strnlen_last_bytes:\n"
 266                "       mv      %0, %4\n"
 267                "strnlen_last_bytes_fixup:\n"
 268                "       addi    %1, #-4\n"
 269                "strnlen_byte_loop:\n"
 270                "1:     ldb     r0, @%1     ||  addi    %0, #-1\n"
 271                "       beqz    r0, strnlen_exit\n"
 272                "       addi    %1, #1\n"
 273                "       bnez    %0, strnlen_byte_loop\n"
 274                "strnlen_exit:\n"
 275                "       sub     %1, r1\n"
 276                "       add3    %0, %1, #1\n"
 277                "       .fillinsn\n"
 278                "9:\n"
 279                ".section .fixup,\"ax\"\n"
 280                "       .balign 4\n"
 281                "4:     addi    %1, #-4\n"
 282                "       .fillinsn\n"
 283                "5:     seth    r1, #high(9b)\n"
 284                "       or3     r1, r1, #low(9b)\n"
 285                "       jmp     r1          ||  ldi     %0, #0\n"
 286                ".previous\n"
 287                ".section __ex_table,\"a\"\n"
 288                "       .balign 4\n"
 289                "       .long 0b,4b\n"
 290                "       .long 1b,5b\n"
 291                ".previous"
 292                : "=&r" (res), "=r" (s)
 293                : "0" (n), "1" (s), "r" (n & 3), "r" (mask), "r"(0x01010101)
 294                : "r0", "r1", "cbit");
 295
 296        /* NOTE: strnlen_user() algorithm:
 297         * {
 298         *   char *p;
 299         *   for (p = s; n-- && *p != '\0'; ++p)
 300         *     ;
 301         *   return p - s + 1;
 302         * }
 303         */
 304
 305        /* NOTE: If a null char. exists, return 0.
 306         * if ((x - 0x01010101) & ~x & 0x80808080)\n"
 307         *   return 0;\n"
 308         */
 309
 310        return res & mask;
 311}
 312
 313#else /* not CONFIG_ISA_DUAL_ISSUE */
 314
 315long strnlen_user(const char __user *s, long n)
 316{
 317        unsigned long mask = -__addr_ok(s);
 318        unsigned long res;
 319
 320        __asm__ __volatile__(
 321                "       and     %0, %5\n"
 322                "       mv      r1, %1\n"
 323                "       beqz    %0, strnlen_exit\n"
 324                "       and3    r0, %1, #3\n"
 325                "       bnez    r0, strnlen_byte_loop\n"
 326                "       cmpui   %0, #4\n"
 327                "       bc      strnlen_byte_loop\n"
 328                "       sll3    r3, %6, #7\n"
 329                "strnlen_word_loop:\n"
 330                "0:     ld      r0, @%1+\n"
 331                "       not     r2, r0\n"
 332                "       sub     r0, %6\n"
 333                "       and     r2, r3\n"
 334                "       and     r2, r0\n"
 335                "       bnez    r2, strnlen_last_bytes_fixup\n"
 336                "       addi    %0, #-4\n"
 337                "       beqz    %0, strnlen_exit\n"
 338                "       bgtz    %0, strnlen_word_loop\n"
 339                "strnlen_last_bytes:\n"
 340                "       mv      %0, %4\n"
 341                "strnlen_last_bytes_fixup:\n"
 342                "       addi    %1, #-4\n"
 343                "strnlen_byte_loop:\n"
 344                "1:     ldb     r0, @%1\n"
 345                "       addi    %0, #-1\n"
 346                "       beqz    r0, strnlen_exit\n"
 347                "       addi    %1, #1\n"
 348                "       bnez    %0, strnlen_byte_loop\n"
 349                "strnlen_exit:\n"
 350                "       sub     %1, r1\n"
 351                "       add3    %0, %1, #1\n"
 352                "       .fillinsn\n"
 353                "9:\n"
 354                ".section .fixup,\"ax\"\n"
 355                "       .balign 4\n"
 356                "4:     addi    %1, #-4\n"
 357                "       .fillinsn\n"
 358                "5:     ldi     %0, #0\n"
 359                "       seth    r1, #high(9b)\n"
 360                "       or3     r1, r1, #low(9b)\n"
 361                "       jmp     r1\n"
 362                ".previous\n"
 363                ".section __ex_table,\"a\"\n"
 364                "       .balign 4\n"
 365                "       .long 0b,4b\n"
 366                "       .long 1b,5b\n"
 367                ".previous"
 368                : "=&r" (res), "=r" (s)
 369                : "0" (n), "1" (s), "r" (n & 3), "r" (mask), "r"(0x01010101)
 370                : "r0", "r1", "r2", "r3", "cbit");
 371
 372        /* NOTE: strnlen_user() algorithm:
 373         * {
 374         *   char *p;
 375         *   for (p = s; n-- && *p != '\0'; ++p)
 376         *     ;
 377         *   return p - s + 1;
 378         * }
 379         */
 380
 381        /* NOTE: If a null char. exists, return 0.
 382         * if ((x - 0x01010101) & ~x & 0x80808080)\n"
 383         *   return 0;\n"
 384         */
 385
 386        return res & mask;
 387}
 388
 389#endif /* CONFIG_ISA_DUAL_ISSUE */
 390
 391