Logo Search packages:      
Sourcecode: linux version File versions  Download package

usercopy.c

/*
 * User address space access functions.
 * The non inlined parts of asm-m32r/uaccess.h are here.
 *
 * Copyright 1997 Andi Kleen <ak@muc.de>
 * Copyright 1997 Linus Torvalds
 * Copyright 2001, 2002, 2004 Hirokazu Takata
 */
#include <linux/prefetch.h>
#include <linux/string.h>
#include <linux/thread_info.h>
#include <asm/uaccess.h>

unsigned long
__generic_copy_to_user(void __user *to, const void *from, unsigned long n)
{
      prefetch(from);
      if (access_ok(VERIFY_WRITE, to, n))
            __copy_user(to,from,n);
      return n;
}

unsigned long
__generic_copy_from_user(void *to, const void __user *from, unsigned long n)
{
      prefetchw(to);
      if (access_ok(VERIFY_READ, from, n))
            __copy_user_zeroing(to,from,n);
      else
            memset(to, 0, n);
      return n;
}


/*
 * Copy a null terminated string from userspace.
 */

#ifdef CONFIG_ISA_DUAL_ISSUE

#define __do_strncpy_from_user(dst,src,count,res)                 \
do {                                                  \
      int __d0, __d1, __d2;                                 \
      __asm__ __volatile__(                                 \
            "     beqz  %1, 2f\n"                     \
            "     .fillinsn\n"                              \
            "0:   ldb   r14, @%3    ||    addi  %3, #1\n"   \
            "     stb   r14, @%4    ||    addi  %4, #1\n"   \
            "     beqz  r14, 1f\n"                    \
            "     addi  %1, #-1\n"                    \
            "     bnez  %1, 0b\n"                     \
            "     .fillinsn\n"                              \
            "1:   sub   %0, %1\n"                     \
            "     .fillinsn\n"                              \
            "2:\n"                                          \
            ".section .fixup,\"ax\"\n"                      \
            "     .balign 4\n"                              \
            "3:   seth  r14, #high(2b)\n"             \
            "     or3   r14, r14, #low(2b)\n"               \
            "     jmp   r14       ||      ldi   %0, #%5\n"  \
            ".previous\n"                                   \
            ".section __ex_table,\"a\"\n"                   \
            "     .balign 4\n"                              \
            "     .long 0b,3b\n"                            \
            ".previous"                               \
            : "=&r"(res), "=&r"(count), "=&r" (__d0), "=&r" (__d1),     \
              "=&r" (__d2)                                  \
            : "i"(-EFAULT), "0"(count), "1"(count), "3"(src),     \
              "4"(dst)                                \
            : "r14", "cbit", "memory");                     \
} while (0)

#else /* not CONFIG_ISA_DUAL_ISSUE */

#define __do_strncpy_from_user(dst,src,count,res)                 \
do {                                                  \
      int __d0, __d1, __d2;                                 \
      __asm__ __volatile__(                                 \
            "     beqz  %1, 2f\n"                     \
            "     .fillinsn\n"                              \
            "0:   ldb   r14, @%3\n"                   \
            "     stb   r14, @%4\n"                   \
            "     addi  %3, #1\n"                     \
            "     addi  %4, #1\n"                     \
            "     beqz  r14, 1f\n"                    \
            "     addi  %1, #-1\n"                    \
            "     bnez  %1, 0b\n"                     \
            "     .fillinsn\n"                              \
            "1:   sub   %0, %1\n"                     \
            "     .fillinsn\n"                              \
            "2:\n"                                          \
            ".section .fixup,\"ax\"\n"                      \
            "     .balign 4\n"                              \
            "3:   ldi   %0, #%5\n"                    \
            "     seth  r14, #high(2b)\n"             \
            "     or3   r14, r14, #low(2b)\n"               \
            "     jmp   r14\n"                              \
            ".previous\n"                                   \
            ".section __ex_table,\"a\"\n"                   \
            "     .balign 4\n"                              \
            "     .long 0b,3b\n"                            \
            ".previous"                               \
            : "=&r"(res), "=&r"(count), "=&r" (__d0), "=&r" (__d1),     \
              "=&r" (__d2)                                  \
            : "i"(-EFAULT), "0"(count), "1"(count), "3"(src),     \
              "4"(dst)                                \
            : "r14", "cbit", "memory");                     \
} while (0)

#endif /* CONFIG_ISA_DUAL_ISSUE */

long
__strncpy_from_user(char *dst, const char __user *src, long count)
{
      long res;
      __do_strncpy_from_user(dst, src, count, res);
      return res;
}

long
strncpy_from_user(char *dst, const char __user *src, long count)
{
      long res = -EFAULT;
      if (access_ok(VERIFY_READ, src, 1))
            __do_strncpy_from_user(dst, src, count, res);
      return res;
}


/*
 * Zero Userspace
 */

#ifdef CONFIG_ISA_DUAL_ISSUE

#define __do_clear_user(addr,size)                          \
do {                                                  \
      int __dst, __c;                                       \
      __asm__ __volatile__(                                 \
            "     beqz  %1, 9f\n"                     \
            "     and3  r14, %0, #3\n"                      \
            "     bnez  r14, 2f\n"                    \
            "     and3  r14, %1, #3\n"                      \
            "     bnez  r14, 2f\n"                    \
            "     and3  %1, %1, #3\n"                       \
            "     beqz  %2, 2f\n"                     \
            "     addi  %0, #-4\n"                    \
            "     .fillinsn\n"                              \
            "0:   ; word clear \n"                    \
            "     st    %6, @+%0    ||    addi  %2, #-1\n"  \
            "     bnez  %2, 0b\n"                     \
            "     beqz  %1, 9f\n"                     \
            "     .fillinsn\n"                              \
            "2:   ; byte clear \n"                    \
            "     stb   %6, @%0         ||      addi  %1, #-1\n"  \
            "     addi  %0, #1\n"                     \
            "     bnez  %1, 2b\n"                     \
            "     .fillinsn\n"                              \
            "9:\n"                                          \
            ".section .fixup,\"ax\"\n"                      \
            "     .balign 4\n"                              \
            "4:   slli  %2, #2\n"                     \
            "     seth  r14, #high(9b)\n"             \
            "     or3   r14, r14, #low(9b)\n"               \
            "     jmp   r14       ||      add   %1, %2\n"   \
            ".previous\n"                                   \
            ".section __ex_table,\"a\"\n"                   \
            "     .balign 4\n"                              \
            "     .long 0b,4b\n"                            \
            "     .long 2b,9b\n"                            \
            ".previous\n"                                   \
            : "=&r"(__dst), "=&r"(size), "=&r"(__c)               \
            : "0"(addr), "1"(size), "2"(size / 4), "r"(0)         \
            : "r14", "cbit", "memory");                     \
} while (0)

#else /* not CONFIG_ISA_DUAL_ISSUE */

#define __do_clear_user(addr,size)                          \
do {                                                  \
      int __dst, __c;                                       \
      __asm__ __volatile__(                                 \
            "     beqz  %1, 9f\n"                     \
            "     and3  r14, %0, #3\n"                      \
            "     bnez  r14, 2f\n"                    \
            "     and3  r14, %1, #3\n"                      \
            "     bnez  r14, 2f\n"                    \
            "     and3  %1, %1, #3\n"                       \
            "     beqz  %2, 2f\n"                     \
            "     addi  %0, #-4\n"                    \
            "     .fillinsn\n"                              \
            "0:   st    %6, @+%0    ; word clear \n"  \
            "     addi  %2, #-1\n"                    \
            "     bnez  %2, 0b\n"                     \
            "     beqz  %1, 9f\n"                     \
            "     .fillinsn\n"                              \
            "2:   stb   %6, @%0           ; byte clear \n"  \
            "     addi  %1, #-1\n"                    \
            "     addi  %0, #1\n"                     \
            "     bnez  %1, 2b\n"                     \
            "     .fillinsn\n"                              \
            "9:\n"                                          \
            ".section .fixup,\"ax\"\n"                      \
            "     .balign 4\n"                              \
            "4:   slli  %2, #2\n"                     \
            "     add   %1, %2\n"                     \
            "     seth  r14, #high(9b)\n"             \
            "     or3   r14, r14, #low(9b)\n"               \
            "     jmp   r14\n"                              \
            ".previous\n"                                   \
            ".section __ex_table,\"a\"\n"                   \
            "     .balign 4\n"                              \
            "     .long 0b,4b\n"                            \
            "     .long 2b,9b\n"                            \
            ".previous\n"                                   \
            : "=&r"(__dst), "=&r"(size), "=&r"(__c)               \
            : "0"(addr), "1"(size), "2"(size / 4), "r"(0)         \
            : "r14", "cbit", "memory");                     \
} while (0)

#endif /* not CONFIG_ISA_DUAL_ISSUE */

unsigned long
clear_user(void __user *to, unsigned long n)
{
      if (access_ok(VERIFY_WRITE, to, n))
            __do_clear_user(to, n);
      return n;
}

unsigned long
__clear_user(void __user *to, unsigned long n)
{
      __do_clear_user(to, n);
      return n;
}

/*
 * Return the size of a string (including the ending 0)
 *
 * Return 0 on exception, a value greater than N if too long
 */

#ifdef CONFIG_ISA_DUAL_ISSUE

long strnlen_user(const char __user *s, long n)
{
      unsigned long mask = -__addr_ok(s);
      unsigned long res;

      __asm__ __volatile__(
            "     and   %0, %5          ||      mv    r1, %1\n"
            "     beqz  %0, strnlen_exit\n"
            "     and3  r0, %1, #3\n"
            "     bnez  r0, strnlen_byte_loop\n"
            "     cmpui %0, #4\n"
            "     bc    strnlen_byte_loop\n"
            "strnlen_word_loop:\n"
            "0:   ld    r0, @%1+\n"
            "     pcmpbz      r0\n"
            "     bc    strnlen_last_bytes_fixup\n"
            "     addi  %0, #-4\n"
            "     beqz  %0, strnlen_exit\n"
            "     bgtz  %0, strnlen_word_loop\n"
            "strnlen_last_bytes:\n"
            "     mv    %0, %4\n"
            "strnlen_last_bytes_fixup:\n"
            "     addi  %1, #-4\n"
            "strnlen_byte_loop:\n"
            "1:   ldb   r0, @%1         ||      addi  %0, #-1\n"
            "     beqz  r0, strnlen_exit\n"
            "     addi  %1, #1\n"
            "     bnez  %0, strnlen_byte_loop\n"
            "strnlen_exit:\n"
            "     sub   %1, r1\n"
            "     add3  %0, %1, #1\n"
            "     .fillinsn\n"
            "9:\n"
            ".section .fixup,\"ax\"\n"
            "     .balign 4\n"
            "4:   addi  %1, #-4\n"
            "     .fillinsn\n"
            "5:   seth  r1, #high(9b)\n"
            "     or3   r1, r1, #low(9b)\n"
            "     jmp   r1        ||      ldi   %0, #0\n"
            ".previous\n"
            ".section __ex_table,\"a\"\n"
            "     .balign 4\n"
            "     .long 0b,4b\n"
            "     .long 1b,5b\n"
            ".previous"
            : "=&r" (res), "=r" (s)
            : "0" (n), "1" (s), "r" (n & 3), "r" (mask), "r"(0x01010101)
            : "r0", "r1", "cbit");

      /* NOTE: strnlen_user() algorithm:
       * {
       *   char *p;
       *   for (p = s; n-- && *p != '\0'; ++p)
       *     ;
       *   return p - s + 1;
       * }
       */

      /* NOTE: If a null char. exists, return 0.
       * if ((x - 0x01010101) & ~x & 0x80808080)\n"
       *   return 0;\n"
       */

      return res & mask;
}

#else /* not CONFIG_ISA_DUAL_ISSUE */

long strnlen_user(const char __user *s, long n)
{
      unsigned long mask = -__addr_ok(s);
      unsigned long res;

      __asm__ __volatile__(
            "     and   %0, %5\n"
            "     mv    r1, %1\n"
            "     beqz  %0, strnlen_exit\n"
            "     and3  r0, %1, #3\n"
            "     bnez  r0, strnlen_byte_loop\n"
            "     cmpui %0, #4\n"
            "     bc    strnlen_byte_loop\n"
            "     sll3  r3, %6, #7\n"
            "strnlen_word_loop:\n"
            "0:   ld    r0, @%1+\n"
            "     not   r2, r0\n"
            "     sub   r0, %6\n"
            "     and   r2, r3\n"
            "     and   r2, r0\n"
            "     bnez  r2, strnlen_last_bytes_fixup\n"
            "     addi  %0, #-4\n"
            "     beqz  %0, strnlen_exit\n"
            "     bgtz  %0, strnlen_word_loop\n"
            "strnlen_last_bytes:\n"
            "     mv    %0, %4\n"
            "strnlen_last_bytes_fixup:\n"
            "     addi  %1, #-4\n"
            "strnlen_byte_loop:\n"
            "1:   ldb   r0, @%1\n"
            "     addi  %0, #-1\n"
            "     beqz  r0, strnlen_exit\n"
            "     addi  %1, #1\n"
            "     bnez  %0, strnlen_byte_loop\n"
            "strnlen_exit:\n"
            "     sub   %1, r1\n"
            "     add3  %0, %1, #1\n"
            "     .fillinsn\n"
            "9:\n"
            ".section .fixup,\"ax\"\n"
            "     .balign 4\n"
            "4:   addi  %1, #-4\n"
            "     .fillinsn\n"
            "5:   ldi   %0, #0\n"
            "     seth  r1, #high(9b)\n"
            "     or3   r1, r1, #low(9b)\n"
            "     jmp   r1\n"
            ".previous\n"
            ".section __ex_table,\"a\"\n"
            "     .balign 4\n"
            "     .long 0b,4b\n"
            "     .long 1b,5b\n"
            ".previous"
            : "=&r" (res), "=r" (s)
            : "0" (n), "1" (s), "r" (n & 3), "r" (mask), "r"(0x01010101)
            : "r0", "r1", "r2", "r3", "cbit");

      /* NOTE: strnlen_user() algorithm:
       * {
       *   char *p;
       *   for (p = s; n-- && *p != '\0'; ++p)
       *     ;
       *   return p - s + 1;
       * }
       */

      /* NOTE: If a null char. exists, return 0.
       * if ((x - 0x01010101) & ~x & 0x80808080)\n"
       *   return 0;\n"
       */

      return res & mask;
}

#endif /* CONFIG_ISA_DUAL_ISSUE */


Generated by  Doxygen 1.6.0   Back to index