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