linux/arch/sparc/lib/user_fixup.c
<<
>>
Prefs
   1/* user_fixup.c: Fix up user copy faults.
   2 *
   3 * Copyright (C) 2004 David S. Miller <davem@redhat.com>
   4 */
   5
   6#include <linux/compiler.h>
   7#include <linux/kernel.h>
   8#include <linux/string.h>
   9#include <linux/errno.h>
  10#include <linux/module.h>
  11
  12#include <asm/uaccess.h>
  13
  14/* Calculating the exact fault address when using
  15 * block loads and stores can be very complicated.
  16 *
  17 * Instead of trying to be clever and handling all
  18 * of the cases, just fix things up simply here.
  19 */
  20
  21static unsigned long compute_size(unsigned long start, unsigned long size, unsigned long *offset)
  22{
  23        unsigned long fault_addr = current_thread_info()->fault_address;
  24        unsigned long end = start + size;
  25
  26        if (fault_addr < start || fault_addr >= end) {
  27                *offset = 0;
  28        } else {
  29                *offset = fault_addr - start;
  30                size = end - fault_addr;
  31        }
  32        return size;
  33}
  34
  35unsigned long copy_from_user_fixup(void *to, const void __user *from, unsigned long size)
  36{
  37        unsigned long offset;
  38
  39        size = compute_size((unsigned long) from, size, &offset);
  40        if (likely(size))
  41                memset(to + offset, 0, size);
  42
  43        return size;
  44}
  45EXPORT_SYMBOL(copy_from_user_fixup);
  46
  47unsigned long copy_to_user_fixup(void __user *to, const void *from, unsigned long size)
  48{
  49        unsigned long offset;
  50
  51        return compute_size((unsigned long) to, size, &offset);
  52}
  53EXPORT_SYMBOL(copy_to_user_fixup);
  54
  55unsigned long copy_in_user_fixup(void __user *to, void __user *from, unsigned long size)
  56{
  57        unsigned long fault_addr = current_thread_info()->fault_address;
  58        unsigned long start = (unsigned long) to;
  59        unsigned long end = start + size;
  60
  61        if (fault_addr >= start && fault_addr < end)
  62                return end - fault_addr;
  63
  64        start = (unsigned long) from;
  65        end = start + size;
  66        if (fault_addr >= start && fault_addr < end)
  67                return end - fault_addr;
  68
  69        return size;
  70}
  71EXPORT_SYMBOL(copy_in_user_fixup);
  72