xref: /openbmc/linux/arch/csky/lib/usercopy.c (revision b8265621)
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 	___copy_from_user(to, from, n);
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 {
18 	___copy_to_user(to, from, n);
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 
112 	if (access_ok(src, 1))
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 {
235 	if (access_ok(to, n))
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);
259