]>
Commit | Line | Data |
---|---|---|
da551281 GR |
1 | // SPDX-License-Identifier: GPL-2.0 |
2 | // Copyright (C) 2018 Hangzhou C-SKY Microsystems co.,ltd. | |
3 | ||
4 | #include <linux/uaccess.h> | |
5 | #include <linux/types.h> | |
6 | ||
7 | unsigned long raw_copy_from_user(void *to, const void *from, | |
8 | unsigned long n) | |
9 | { | |
51bb38cb | 10 | ___copy_from_user(to, from, n); |
da551281 GR |
11 | return n; |
12 | } | |
13 | EXPORT_SYMBOL(raw_copy_from_user); | |
14 | ||
15 | unsigned long raw_copy_to_user(void *to, const void *from, | |
16 | unsigned long n) | |
17 | { | |
51bb38cb | 18 | ___copy_to_user(to, from, n); |
da551281 GR |
19 | return n; |
20 | } | |
21 | EXPORT_SYMBOL(raw_copy_to_user); | |
22 | ||
23 | ||
24 | /* | |
25 | * copy a null terminated string from userspace. | |
26 | */ | |
27 | #define __do_strncpy_from_user(dst, src, count, res) \ | |
28 | do { \ | |
29 | int tmp; \ | |
30 | long faultres; \ | |
31 | asm volatile( \ | |
32 | " cmpnei %3, 0 \n" \ | |
33 | " bf 4f \n" \ | |
34 | "1: cmpnei %1, 0 \n" \ | |
35 | " bf 5f \n" \ | |
36 | "2: ldb %4, (%3, 0) \n" \ | |
37 | " stb %4, (%2, 0) \n" \ | |
38 | " cmpnei %4, 0 \n" \ | |
39 | " bf 3f \n" \ | |
40 | " addi %3, 1 \n" \ | |
41 | " addi %2, 1 \n" \ | |
42 | " subi %1, 1 \n" \ | |
43 | " br 1b \n" \ | |
44 | "3: subu %0, %1 \n" \ | |
45 | " br 5f \n" \ | |
46 | "4: mov %0, %5 \n" \ | |
47 | " br 5f \n" \ | |
48 | ".section __ex_table, \"a\" \n" \ | |
49 | ".align 2 \n" \ | |
50 | ".long 2b, 4b \n" \ | |
51 | ".previous \n" \ | |
52 | "5: \n" \ | |
53 | : "=r"(res), "=r"(count), "=r"(dst), \ | |
54 | "=r"(src), "=r"(tmp), "=r"(faultres) \ | |
55 | : "5"(-EFAULT), "0"(count), "1"(count), \ | |
56 | "2"(dst), "3"(src) \ | |
57 | : "memory", "cc"); \ | |
58 | } while (0) | |
59 | ||
60 | /* | |
61 | * __strncpy_from_user: - Copy a NUL terminated string from userspace, | |
62 | * with less checking. | |
63 | * @dst: Destination address, in kernel space. This buffer must be at | |
64 | * least @count bytes long. | |
65 | * @src: Source address, in user space. | |
66 | * @count: Maximum number of bytes to copy, including the trailing NUL. | |
67 | * | |
68 | * Copies a NUL-terminated string from userspace to kernel space. | |
69 | * Caller must check the specified block with access_ok() before calling | |
70 | * this function. | |
71 | * | |
72 | * On success, returns the length of the string (not including the trailing | |
73 | * NUL). | |
74 | * | |
75 | * If access to userspace fails, returns -EFAULT (some data may have been | |
76 | * copied). | |
77 | * | |
78 | * If @count is smaller than the length of the string, copies @count bytes | |
79 | * and returns @count. | |
80 | */ | |
81 | long __strncpy_from_user(char *dst, const char *src, long count) | |
82 | { | |
83 | long res; | |
84 | ||
85 | __do_strncpy_from_user(dst, src, count, res); | |
86 | return res; | |
87 | } | |
88 | EXPORT_SYMBOL(__strncpy_from_user); | |
89 | ||
90 | /* | |
91 | * strncpy_from_user: - Copy a NUL terminated string from userspace. | |
92 | * @dst: Destination address, in kernel space. This buffer must be at | |
93 | * least @count bytes long. | |
94 | * @src: Source address, in user space. | |
95 | * @count: Maximum number of bytes to copy, including the trailing NUL. | |
96 | * | |
97 | * Copies a NUL-terminated string from userspace to kernel space. | |
98 | * | |
99 | * On success, returns the length of the string (not including the trailing | |
100 | * NUL). | |
101 | * | |
102 | * If access to userspace fails, returns -EFAULT (some data may have been | |
103 | * copied). | |
104 | * | |
105 | * If @count is smaller than the length of the string, copies @count bytes | |
106 | * and returns @count. | |
107 | */ | |
108 | long strncpy_from_user(char *dst, const char *src, long count) | |
109 | { | |
110 | long res = -EFAULT; | |
111 | ||
96d4f267 | 112 | if (access_ok(src, 1)) |
da551281 GR |
113 | __do_strncpy_from_user(dst, src, count, res); |
114 | return res; | |
115 | } | |
116 | EXPORT_SYMBOL(strncpy_from_user); | |
117 | ||
118 | /* | |
119 | * strlen_user: - Get the size of a string in user space. | |
120 | * @str: The string to measure. | |
121 | * @n: The maximum valid length | |
122 | * | |
123 | * Get the size of a NUL-terminated string in user space. | |
124 | * | |
125 | * Returns the size of the string INCLUDING the terminating NUL. | |
126 | * On exception, returns 0. | |
127 | * If the string is too long, returns a value greater than @n. | |
128 | */ | |
129 | long strnlen_user(const char *s, long n) | |
130 | { | |
131 | unsigned long res, tmp; | |
132 | ||
133 | if (s == NULL) | |
134 | return 0; | |
135 | ||
136 | asm volatile( | |
137 | " cmpnei %1, 0 \n" | |
138 | " bf 3f \n" | |
139 | "1: cmpnei %0, 0 \n" | |
140 | " bf 3f \n" | |
141 | "2: ldb %3, (%1, 0) \n" | |
142 | " cmpnei %3, 0 \n" | |
143 | " bf 3f \n" | |
144 | " subi %0, 1 \n" | |
145 | " addi %1, 1 \n" | |
146 | " br 1b \n" | |
147 | "3: subu %2, %0 \n" | |
148 | " addi %2, 1 \n" | |
149 | " br 5f \n" | |
150 | "4: movi %0, 0 \n" | |
151 | " br 5f \n" | |
152 | ".section __ex_table, \"a\" \n" | |
153 | ".align 2 \n" | |
154 | ".long 2b, 4b \n" | |
155 | ".previous \n" | |
156 | "5: \n" | |
157 | : "=r"(n), "=r"(s), "=r"(res), "=r"(tmp) | |
158 | : "0"(n), "1"(s), "2"(n) | |
159 | : "memory", "cc"); | |
160 | ||
161 | return res; | |
162 | } | |
163 | EXPORT_SYMBOL(strnlen_user); | |
164 | ||
165 | #define __do_clear_user(addr, size) \ | |
166 | do { \ | |
167 | int __d0, zvalue, tmp; \ | |
168 | \ | |
169 | asm volatile( \ | |
170 | "0: cmpnei %1, 0 \n" \ | |
171 | " bf 7f \n" \ | |
172 | " mov %3, %1 \n" \ | |
173 | " andi %3, 3 \n" \ | |
174 | " cmpnei %3, 0 \n" \ | |
175 | " bf 1f \n" \ | |
176 | " br 5f \n" \ | |
177 | "1: cmplti %0, 32 \n" /* 4W */ \ | |
178 | " bt 3f \n" \ | |
179 | "8: stw %2, (%1, 0) \n" \ | |
180 | "10: stw %2, (%1, 4) \n" \ | |
181 | "11: stw %2, (%1, 8) \n" \ | |
182 | "12: stw %2, (%1, 12) \n" \ | |
183 | "13: stw %2, (%1, 16) \n" \ | |
184 | "14: stw %2, (%1, 20) \n" \ | |
185 | "15: stw %2, (%1, 24) \n" \ | |
186 | "16: stw %2, (%1, 28) \n" \ | |
187 | " addi %1, 32 \n" \ | |
188 | " subi %0, 32 \n" \ | |
189 | " br 1b \n" \ | |
190 | "3: cmplti %0, 4 \n" /* 1W */ \ | |
191 | " bt 5f \n" \ | |
192 | "4: stw %2, (%1, 0) \n" \ | |
193 | " addi %1, 4 \n" \ | |
194 | " subi %0, 4 \n" \ | |
195 | " br 3b \n" \ | |
196 | "5: cmpnei %0, 0 \n" /* 1B */ \ | |
197 | "9: bf 7f \n" \ | |
198 | "6: stb %2, (%1, 0) \n" \ | |
199 | " addi %1, 1 \n" \ | |
200 | " subi %0, 1 \n" \ | |
201 | " br 5b \n" \ | |
202 | ".section __ex_table,\"a\" \n" \ | |
203 | ".align 2 \n" \ | |
204 | ".long 8b, 9b \n" \ | |
205 | ".long 10b, 9b \n" \ | |
206 | ".long 11b, 9b \n" \ | |
207 | ".long 12b, 9b \n" \ | |
208 | ".long 13b, 9b \n" \ | |
209 | ".long 14b, 9b \n" \ | |
210 | ".long 15b, 9b \n" \ | |
211 | ".long 16b, 9b \n" \ | |
212 | ".long 4b, 9b \n" \ | |
213 | ".long 6b, 9b \n" \ | |
214 | ".previous \n" \ | |
215 | "7: \n" \ | |
216 | : "=r"(size), "=r" (__d0), \ | |
217 | "=r"(zvalue), "=r"(tmp) \ | |
218 | : "0"(size), "1"(addr), "2"(0) \ | |
219 | : "memory", "cc"); \ | |
220 | } while (0) | |
221 | ||
222 | /* | |
223 | * clear_user: - Zero a block of memory in user space. | |
224 | * @to: Destination address, in user space. | |
225 | * @n: Number of bytes to zero. | |
226 | * | |
227 | * Zero a block of memory in user space. | |
228 | * | |
229 | * Returns number of bytes that could not be cleared. | |
230 | * On success, this will be zero. | |
231 | */ | |
232 | unsigned long | |
233 | clear_user(void __user *to, unsigned long n) | |
234 | { | |
96d4f267 | 235 | if (access_ok(to, n)) |
da551281 GR |
236 | __do_clear_user(to, n); |
237 | return n; | |
238 | } | |
239 | EXPORT_SYMBOL(clear_user); | |
240 | ||
241 | /* | |
242 | * __clear_user: - Zero a block of memory in user space, with less checking. | |
243 | * @to: Destination address, in user space. | |
244 | * @n: Number of bytes to zero. | |
245 | * | |
246 | * Zero a block of memory in user space. Caller must check | |
247 | * the specified block with access_ok() before calling this function. | |
248 | * | |
249 | * Returns number of bytes that could not be cleared. | |
250 | * On success, this will be zero. | |
251 | */ | |
252 | unsigned long | |
253 | __clear_user(void __user *to, unsigned long n) | |
254 | { | |
255 | __do_clear_user(to, n); | |
256 | return n; | |
257 | } | |
258 | EXPORT_SYMBOL(__clear_user); |