diff options
Diffstat (limited to 'arch/sparc/lib/user_fixup.c')
-rw-r--r-- | arch/sparc/lib/user_fixup.c | 66 |
1 files changed, 66 insertions, 0 deletions
diff --git a/arch/sparc/lib/user_fixup.c b/arch/sparc/lib/user_fixup.c new file mode 100644 index 000000000000..05a361b0a1a4 --- /dev/null +++ b/arch/sparc/lib/user_fixup.c | |||
@@ -0,0 +1,66 @@ | |||
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. | ||
14 | * | ||
15 | * Instead of trying to be clever and handling all | ||
16 | * of the cases, just fix things up simply here. | ||
17 | */ | ||
18 | |||
19 | static unsigned long compute_size(unsigned long start, unsigned long size, unsigned long *offset) | ||
20 | { | ||
21 | unsigned long fault_addr = current_thread_info()->fault_address; | ||
22 | unsigned long end = start + size; | ||
23 | |||
24 | if (fault_addr < start || fault_addr >= end) { | ||
25 | *offset = 0; | ||
26 | } else { | ||
27 | *offset = fault_addr - start; | ||
28 | size = end - fault_addr; | ||
29 | } | ||
30 | return size; | ||
31 | } | ||
32 | |||
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); | ||
40 | |||
41 | return size; | ||
42 | } | ||
43 | |||
44 | unsigned long copy_to_user_fixup(void __user *to, const void *from, unsigned long size) | ||
45 | { | ||
46 | unsigned long offset; | ||
47 | |||
48 | return compute_size((unsigned long) to, size, &offset); | ||
49 | } | ||
50 | |||
51 | unsigned long copy_in_user_fixup(void __user *to, void __user *from, unsigned long size) | ||
52 | { | ||
53 | unsigned long fault_addr = current_thread_info()->fault_address; | ||
54 | unsigned long start = (unsigned long) to; | ||
55 | unsigned long end = start + size; | ||
56 | |||
57 | if (fault_addr >= start && fault_addr < end) | ||
58 | return end - fault_addr; | ||
59 | |||
60 | start = (unsigned long) from; | ||
61 | end = start + size; | ||
62 | if (fault_addr >= start && fault_addr < end) | ||
63 | return end - fault_addr; | ||
64 | |||
65 | return size; | ||
66 | } | ||