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

usercopy_64.c

/* 
 * User address space access functions.
 *
 * Copyright 1997 Andi Kleen <ak@muc.de>
 * Copyright 1997 Linus Torvalds
 * Copyright 2002 Andi Kleen <ak@suse.de>
 */
#include <linux/module.h>
#include <asm/uaccess.h>

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

#define __do_strncpy_from_user(dst,src,count,res)                    \
do {                                                     \
      long __d0, __d1, __d2;                                   \
      might_sleep();                                           \
      __asm__ __volatile__(                                    \
            "     testq %1,%1\n"                               \
            "     jz 2f\n"                               \
            "0:   lodsb\n"                               \
            "     stosb\n"                               \
            "     testb %%al,%%al\n"                           \
            "     jz 1f\n"                               \
            "     decq %1\n"                             \
            "     jnz 0b\n"                              \
            "1:   subq %1,%0\n"                                \
            "2:\n"                                             \
            ".section .fixup,\"ax\"\n"                         \
            "3:   movq %5,%0\n"                                \
            "     jmp 2b\n"                              \
            ".previous\n"                                      \
            ".section __ex_table,\"a\"\n"                      \
            "     .align 8\n"                            \
            "     .quad 0b,3b\n"                               \
            ".previous"                                  \
            : "=r"(res), "=c"(count), "=&a" (__d0), "=&S" (__d1),    \
              "=&D" (__d2)                                     \
            : "i"(-EFAULT), "0"(count), "1"(count), "3"(src), "4"(dst) \
            : "memory");                                       \
} while (0)

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

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

/*
 * Zero Userspace
 */

unsigned long __clear_user(void __user *addr, unsigned long size)
{
      long __d0;
      might_sleep();
      /* no memory constraint because it doesn't change any memory gcc knows
         about */
      asm volatile(
            "     testq  %[size8],%[size8]\n"
            "     jz     4f\n"
            "0:   movq %[zero],(%[dst])\n"
            "     addq   %[eight],%[dst]\n"
            "     decl %%ecx ; jnz   0b\n"
            "4:   movq  %[size1],%%rcx\n"
            "     testl %%ecx,%%ecx\n"
            "     jz     2f\n"
            "1:   movb   %b[zero],(%[dst])\n"
            "     incq   %[dst]\n"
            "     decl %%ecx ; jnz  1b\n"
            "2:\n"
            ".section .fixup,\"ax\"\n"
            "3:   lea 0(%[size1],%[size8],8),%[size8]\n"
            "     jmp 2b\n"
            ".previous\n"
            ".section __ex_table,\"a\"\n"
            "       .align 8\n"
            "     .quad 0b,3b\n"
            "     .quad 1b,2b\n"
            ".previous"
            : [size8] "=c"(size), [dst] "=&D" (__d0)
            : [size1] "r"(size & 7), "[size8]" (size / 8), "[dst]"(addr),
              [zero] "r" (0UL), [eight] "r" (8UL));
      return size;
}
EXPORT_SYMBOL(__clear_user);

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

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

long __strnlen_user(const char __user *s, long n)
{
      long res = 0;
      char c;

      while (1) {
            if (res>n)
                  return n+1;
            if (__get_user(c, s))
                  return 0;
            if (!c)
                  return res+1;
            res++;
            s++;
      }
}
EXPORT_SYMBOL(__strnlen_user);

long strnlen_user(const char __user *s, long n)
{
      if (!access_ok(VERIFY_READ, s, n))
            return 0;
      return __strnlen_user(s, n);
}
EXPORT_SYMBOL(strnlen_user);

long strlen_user(const char __user *s)
{
      long res = 0;
      char c;

      for (;;) {
            if (get_user(c, s))
                  return 0;
            if (!c)
                  return res+1;
            res++;
            s++;
      }
}
EXPORT_SYMBOL(strlen_user);

unsigned long copy_in_user(void __user *to, const void __user *from, unsigned len)
{
      if (access_ok(VERIFY_WRITE, to, len) && access_ok(VERIFY_READ, from, len)) { 
            return copy_user_generic((__force void *)to, (__force void *)from, len);
      } 
      return len;       
}
EXPORT_SYMBOL(copy_in_user);


Generated by  Doxygen 1.6.0   Back to index