Commit | Line | Data |
---|---|---|
1da177e4 LT |
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 <asm/uaccess.h> | |
11 | ||
12 | /* Calculating the exact fault address when using | |
13 | * block loads and stores can be very complicated. | |
efdc1e20 | 14 | * |
1da177e4 LT |
15 | * Instead of trying to be clever and handling all |
16 | * of the cases, just fix things up simply here. | |
17 | */ | |
18 | ||
efdc1e20 | 19 | static unsigned long compute_size(unsigned long start, unsigned long size, unsigned long *offset) |
1da177e4 | 20 | { |
efdc1e20 DM |
21 | unsigned long fault_addr = current_thread_info()->fault_address; |
22 | unsigned long end = start + size; | |
1da177e4 | 23 | |
efdc1e20 DM |
24 | if (fault_addr < start || fault_addr >= end) { |
25 | *offset = 0; | |
26 | } else { | |
b270ee8a | 27 | *offset = fault_addr - start; |
efdc1e20 | 28 | size = end - fault_addr; |
1da177e4 | 29 | } |
efdc1e20 DM |
30 | return size; |
31 | } | |
1da177e4 | 32 | |
efdc1e20 DM |
33 | unsigned long copy_from_user_fixup(void *to, const void __user *from, unsigned long size) |
34 | { | |
35 | unsigned long offset; | |
36 | ||
37 | size = compute_size((unsigned long) from, size, &offset); | |
38 | if (likely(size)) | |
39 | memset(to + offset, 0, size); | |
1da177e4 LT |
40 | |
41 | return size; | |
42 | } | |
43 | ||
44 | unsigned long copy_to_user_fixup(void __user *to, const void *from, unsigned long size) | |
45 | { | |
efdc1e20 | 46 | unsigned long offset; |
1da177e4 | 47 | |
efdc1e20 | 48 | return compute_size((unsigned long) to, size, &offset); |
1da177e4 LT |
49 | } |
50 | ||
51 | unsigned long copy_in_user_fixup(void __user *to, void __user *from, unsigned long size) | |
52 | { | |
efdc1e20 DM |
53 | unsigned long fault_addr = current_thread_info()->fault_address; |
54 | unsigned long start = (unsigned long) to; | |
55 | unsigned long end = start + size; | |
1da177e4 | 56 | |
efdc1e20 DM |
57 | if (fault_addr >= start && fault_addr < end) |
58 | return end - fault_addr; | |
1da177e4 | 59 | |
efdc1e20 DM |
60 | start = (unsigned long) from; |
61 | end = start + size; | |
62 | if (fault_addr >= start && fault_addr < end) | |
63 | return end - fault_addr; | |
1da177e4 LT |
64 | |
65 | return size; | |
66 | } |