Loading...
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
7unsigned long raw_copy_from_user(void *to, const void *from,
8 unsigned long n)
9{
10 ___copy_from_user(to, from, n);
11 return n;
12}
13EXPORT_SYMBOL(raw_copy_from_user);
14
15unsigned long raw_copy_to_user(void *to, const void *from,
16 unsigned long n)
17{
18 ___copy_to_user(to, from, n);
19 return n;
20}
21EXPORT_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) \
28do { \
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 */
81long __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}
88EXPORT_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 */
108long strncpy_from_user(char *dst, const char *src, long count)
109{
110 long res = -EFAULT;
111
112 if (access_ok(src, 1))
113 __do_strncpy_from_user(dst, src, count, res);
114 return res;
115}
116EXPORT_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 */
129long 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}
163EXPORT_SYMBOL(strnlen_user);
164
165#define __do_clear_user(addr, size) \
166do { \
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 */
232unsigned long
233clear_user(void __user *to, unsigned long n)
234{
235 if (access_ok(to, n))
236 __do_clear_user(to, n);
237 return n;
238}
239EXPORT_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 */
252unsigned long
253__clear_user(void __user *to, unsigned long n)
254{
255 __do_clear_user(to, n);
256 return n;
257}
258EXPORT_SYMBOL(__clear_user);
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
7unsigned long raw_copy_from_user(void *to, const void *from,
8 unsigned long n)
9{
10 if (access_ok(from, n))
11 __copy_user_zeroing(to, from, n);
12 else
13 memset(to, 0, n);
14 return n;
15}
16EXPORT_SYMBOL(raw_copy_from_user);
17
18unsigned long raw_copy_to_user(void *to, const void *from,
19 unsigned long n)
20{
21 if (access_ok(to, n))
22 __copy_user(to, from, n);
23 return n;
24}
25EXPORT_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) \
32do { \
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 */
85long __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}
92EXPORT_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 */
112long strncpy_from_user(char *dst, const char *src, long count)
113{
114 long res = -EFAULT;
115
116 if (access_ok(src, 1))
117 __do_strncpy_from_user(dst, src, count, res);
118 return res;
119}
120EXPORT_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 */
133long 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}
167EXPORT_SYMBOL(strnlen_user);
168
169#define __do_clear_user(addr, size) \
170do { \
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 */
236unsigned long
237clear_user(void __user *to, unsigned long n)
238{
239 if (access_ok(to, n))
240 __do_clear_user(to, n);
241 return n;
242}
243EXPORT_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 */
256unsigned long
257__clear_user(void __user *to, unsigned long n)
258{
259 __do_clear_user(to, n);
260 return n;
261}
262EXPORT_SYMBOL(__clear_user);