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