xref: /openbmc/linux/arch/csky/lib/usercopy.c (revision de528723)
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 {
10 	if (access_ok(from, n))
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 {
21 	if (access_ok(to, n))
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 
116 	if (access_ok(src, 1))
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 {
239 	if (access_ok(to, n))
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);
263