1 | /* |
---|
2 | * User address space access functions. |
---|
3 | * |
---|
4 | * Copyright 1997 Andi Kleen <ak@muc.de> |
---|
5 | * Copyright 1997 Linus Torvalds |
---|
6 | * Copyright 2002 Andi Kleen <ak@suse.de> |
---|
7 | */ |
---|
8 | |
---|
9 | #include <xen/config.h> |
---|
10 | #include <xen/lib.h> |
---|
11 | #include <asm/uaccess.h> |
---|
12 | |
---|
13 | unsigned long __copy_to_user_ll(void __user *to, const void *from, unsigned n) |
---|
14 | { |
---|
15 | unsigned long __d0, __d1, __d2, __n = n; |
---|
16 | __asm__ __volatile__( |
---|
17 | " cmp $"STR(2*BYTES_PER_LONG-1)",%0\n" |
---|
18 | " jbe 1f\n" |
---|
19 | " mov %1,%0\n" |
---|
20 | " neg %0\n" |
---|
21 | " and $"STR(BYTES_PER_LONG-1)",%0\n" |
---|
22 | " sub %0,%3\n" |
---|
23 | "4: rep; movsb\n" /* make 'to' address aligned */ |
---|
24 | " mov %3,%0\n" |
---|
25 | " shr $"STR(LONG_BYTEORDER)",%0\n" |
---|
26 | " and $"STR(BYTES_PER_LONG-1)",%3\n" |
---|
27 | " .align 2,0x90\n" |
---|
28 | "0: rep; movs"__OS"\n" /* as many words as possible... */ |
---|
29 | " mov %3,%0\n" |
---|
30 | "1: rep; movsb\n" /* ...remainder copied as bytes */ |
---|
31 | "2:\n" |
---|
32 | ".section .fixup,\"ax\"\n" |
---|
33 | "5: add %3,%0\n" |
---|
34 | " jmp 2b\n" |
---|
35 | "3: lea 0(%3,%0,"STR(BYTES_PER_LONG)"),%0\n" |
---|
36 | " jmp 2b\n" |
---|
37 | ".previous\n" |
---|
38 | ".section __ex_table,\"a\"\n" |
---|
39 | " "__FIXUP_ALIGN"\n" |
---|
40 | " "__FIXUP_WORD" 4b,5b\n" |
---|
41 | " "__FIXUP_WORD" 0b,3b\n" |
---|
42 | " "__FIXUP_WORD" 1b,2b\n" |
---|
43 | ".previous" |
---|
44 | : "=&c"(__n), "=&D" (__d0), "=&S" (__d1), "=r"(__d2) |
---|
45 | : "3"(__n), "0"(__n), "1"(to), "2"(from) |
---|
46 | : "memory"); |
---|
47 | return (unsigned)__n; |
---|
48 | } |
---|
49 | |
---|
50 | unsigned long |
---|
51 | __copy_from_user_ll(void *to, const void __user *from, unsigned n) |
---|
52 | { |
---|
53 | unsigned long __d0, __d1, __d2, __n = n; |
---|
54 | __asm__ __volatile__( |
---|
55 | " cmp $"STR(2*BYTES_PER_LONG-1)",%0\n" |
---|
56 | " jbe 1f\n" |
---|
57 | " mov %1,%0\n" |
---|
58 | " neg %0\n" |
---|
59 | " and $"STR(BYTES_PER_LONG-1)",%0\n" |
---|
60 | " sub %0,%3\n" |
---|
61 | "4: rep; movsb\n" /* make 'to' address aligned */ |
---|
62 | " mov %3,%0\n" |
---|
63 | " shr $"STR(LONG_BYTEORDER)",%0\n" |
---|
64 | " and $"STR(BYTES_PER_LONG-1)",%3\n" |
---|
65 | " .align 2,0x90\n" |
---|
66 | "0: rep; movs"__OS"\n" /* as many words as possible... */ |
---|
67 | " mov %3,%0\n" |
---|
68 | "1: rep; movsb\n" /* ...remainder copied as bytes */ |
---|
69 | "2:\n" |
---|
70 | ".section .fixup,\"ax\"\n" |
---|
71 | "5: add %3,%0\n" |
---|
72 | " jmp 6f\n" |
---|
73 | "3: lea 0(%3,%0,"STR(BYTES_PER_LONG)"),%0\n" |
---|
74 | "6: push %0\n" |
---|
75 | " push %%"__OP"ax\n" |
---|
76 | " xor %%eax,%%eax\n" |
---|
77 | " rep; stosb\n" |
---|
78 | " pop %%"__OP"ax\n" |
---|
79 | " pop %0\n" |
---|
80 | " jmp 2b\n" |
---|
81 | ".previous\n" |
---|
82 | ".section __ex_table,\"a\"\n" |
---|
83 | " "__FIXUP_ALIGN"\n" |
---|
84 | " "__FIXUP_WORD" 4b,5b\n" |
---|
85 | " "__FIXUP_WORD" 0b,3b\n" |
---|
86 | " "__FIXUP_WORD" 1b,6b\n" |
---|
87 | ".previous" |
---|
88 | : "=&c"(__n), "=&D" (__d0), "=&S" (__d1), "=r"(__d2) |
---|
89 | : "3"(__n), "0"(__n), "1"(to), "2"(from) |
---|
90 | : "memory"); |
---|
91 | return (unsigned)__n; |
---|
92 | } |
---|
93 | |
---|
94 | /** |
---|
95 | * copy_to_user: - Copy a block of data into user space. |
---|
96 | * @to: Destination address, in user space. |
---|
97 | * @from: Source address, in kernel space. |
---|
98 | * @n: Number of bytes to copy. |
---|
99 | * |
---|
100 | * Context: User context only. This function may sleep. |
---|
101 | * |
---|
102 | * Copy data from kernel space to user space. |
---|
103 | * |
---|
104 | * Returns number of bytes that could not be copied. |
---|
105 | * On success, this will be zero. |
---|
106 | */ |
---|
107 | unsigned long |
---|
108 | copy_to_user(void __user *to, const void *from, unsigned n) |
---|
109 | { |
---|
110 | if (access_ok(to, n)) |
---|
111 | n = __copy_to_user(to, from, n); |
---|
112 | return n; |
---|
113 | } |
---|
114 | |
---|
115 | /** |
---|
116 | * copy_from_user: - Copy a block of data from user space. |
---|
117 | * @to: Destination address, in kernel space. |
---|
118 | * @from: Source address, in user space. |
---|
119 | * @n: Number of bytes to copy. |
---|
120 | * |
---|
121 | * Context: User context only. This function may sleep. |
---|
122 | * |
---|
123 | * Copy data from user space to kernel space. |
---|
124 | * |
---|
125 | * Returns number of bytes that could not be copied. |
---|
126 | * On success, this will be zero. |
---|
127 | * |
---|
128 | * If some data could not be copied, this function will pad the copied |
---|
129 | * data to the requested size using zero bytes. |
---|
130 | */ |
---|
131 | unsigned long |
---|
132 | copy_from_user(void *to, const void __user *from, unsigned n) |
---|
133 | { |
---|
134 | if (access_ok(from, n)) |
---|
135 | n = __copy_from_user(to, from, n); |
---|
136 | else |
---|
137 | memset(to, 0, n); |
---|
138 | return n; |
---|
139 | } |
---|